Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79ff5357ac | |||
| 2989ffd911 | |||
| 0510aafead | |||
| f6feec3090 | |||
| b3a8d96787 | |||
| ebc59bc4cf | |||
| 565453fe9e | |||
| 3e44e0ebe7 | |||
| f255d10c94 | |||
| b683ddacab | |||
| 4fbf00bfea | |||
| e64ba9da09 | |||
| a8a160324e | |||
| c12a8a7bfa | |||
| 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 | |||
| 2b236b2a35 | |||
| e59699b7fd | |||
| e9f3c66a3b | |||
| dc1dc18824 | |||
| 014e73f44c | |||
| ee7c25727b | |||
| 79f0ba930b | |||
| c5edbfba8e | |||
| 91c689a41f |
+2
-2
@@ -1,7 +1,7 @@
|
||||
language: objective-c
|
||||
osx_image: xcode7
|
||||
xcode_project: LFLiveKit.xcodeproj
|
||||
xcode_project: FrameWork/LFLiveKit.xcodeproj
|
||||
xcode_scheme: LFLiveKit
|
||||
|
||||
script:
|
||||
- xctool -project LFLiveKit.xcodeproj -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>2.1</string>
|
||||
<string>2.6</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
+17
-28
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -14,10 +14,10 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2D23E791D348F3D00B34CA8"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
BlueprintIdentifier = "84D003751DB8FE1000560583"
|
||||
BuildableName = "LFLiveKitFramework-universal"
|
||||
BlueprintName = "LFLiveKitFramework-universal"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
@@ -29,15 +29,6 @@
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2D23E791D348F3D00B34CA8"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
@@ -51,16 +42,15 @@
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2D23E791D348F3D00B34CA8"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
BlueprintIdentifier = "84D003751DB8FE1000560583"
|
||||
BuildableName = "LFLiveKitFramework-universal"
|
||||
BlueprintName = "LFLiveKitFramework-universal"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
@@ -70,16 +60,15 @@
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2D23E791D348F3D00B34CA8"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
BlueprintIdentifier = "84D003751DB8FE1000560583"
|
||||
BuildableName = "LFLiveKitFramework-universal"
|
||||
BlueprintName = "LFLiveKitFramework-universal"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
+17
-28
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -14,10 +14,10 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2C8FAC01D3DB8B3008D44B5"
|
||||
BuildableName = "LFLiveKitSwiftDemo.app"
|
||||
BlueprintName = "LFLiveKitSwiftDemo"
|
||||
ReferencedContainer = "container:LFLiveKitSwiftDemo.xcodeproj">
|
||||
BlueprintIdentifier = "8495F66A1DB8F14600542124"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKitFramework"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
@@ -29,15 +29,6 @@
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2C8FAC01D3DB8B3008D44B5"
|
||||
BuildableName = "LFLiveKitSwiftDemo.app"
|
||||
BlueprintName = "LFLiveKitSwiftDemo"
|
||||
ReferencedContainer = "container:LFLiveKitSwiftDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
@@ -51,16 +42,15 @@
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2C8FAC01D3DB8B3008D44B5"
|
||||
BuildableName = "LFLiveKitSwiftDemo.app"
|
||||
BlueprintName = "LFLiveKitSwiftDemo"
|
||||
ReferencedContainer = "container:LFLiveKitSwiftDemo.xcodeproj">
|
||||
BlueprintIdentifier = "8495F66A1DB8F14600542124"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKitFramework"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
@@ -70,16 +60,15 @@
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2C8FAC01D3DB8B3008D44B5"
|
||||
BuildableName = "LFLiveKitSwiftDemo.app"
|
||||
BlueprintName = "LFLiveKitSwiftDemo"
|
||||
ReferencedContainer = "container:LFLiveKitSwiftDemo.xcodeproj">
|
||||
BlueprintIdentifier = "8495F66A1DB8F14600542124"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKitFramework"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
@@ -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>
|
||||
+1
-3
@@ -2,7 +2,7 @@
|
||||
Pod::Spec.new do |s|
|
||||
|
||||
s.name = "LFLiveKit"
|
||||
s.version = "2.1"
|
||||
s.version = "2.6"
|
||||
s.summary = "LaiFeng ios Live. LFLiveKit."
|
||||
s.homepage = "https://github.com/chenliming777"
|
||||
s.license = { :type => "MIT", :file => "LICENSE" }
|
||||
@@ -11,12 +11,10 @@ Pod::Spec.new do |s|
|
||||
s.ios.deployment_target = "7.0"
|
||||
s.source = { :git => "https://github.com/LaiFengiOS/LFLiveKit.git", :tag => "#{s.version}" }
|
||||
s.source_files = "LFLiveKit/**/*.{h,m,mm,cpp,c}"
|
||||
#s.public_header_files = "LFLiveKit/**/*.h"
|
||||
s.public_header_files = ['LFLiveKit/*.h', 'LFLiveKit/objects/*.h', 'LFLiveKit/configuration/*.h']
|
||||
|
||||
s.frameworks = "VideoToolbox", "AudioToolbox","AVFoundation","Foundation","UIKit"
|
||||
s.libraries = "c++", "z"
|
||||
|
||||
s.requires_arc = true
|
||||
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:LFLiveKit.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
@@ -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>
|
||||
@@ -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>
|
||||
@@ -15,6 +16,8 @@
|
||||
#import "LFLiveVideoConfiguration.h"
|
||||
#import "LFLiveDebug.h"
|
||||
|
||||
|
||||
|
||||
typedef NS_ENUM(NSInteger,LFLiveCaptureType) {
|
||||
LFLiveCaptureAudio, //< capture only audio
|
||||
LFLiveCaptureVideo, //< capture onlt video
|
||||
@@ -113,7 +116,16 @@ typedef NS_ENUM(NSInteger,LFLiveCaptureTypeMask) {
|
||||
/*** The warterMarkView control whether the watermark is displayed or not ,if set ni,will remove watermark,otherwise add.
|
||||
set alpha represent mix.Position relative to outVideoSize.
|
||||
*.*/
|
||||
@property (nonatomic, strong) UIView *warterMarkView;
|
||||
@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
|
||||
///=============================================================================
|
||||
@@ -126,7 +138,7 @@ typedef NS_ENUM(NSInteger,LFLiveCaptureTypeMask) {
|
||||
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;
|
||||
|
||||
/**
|
||||
The designated initializer. Multiple instances with the same configuration will make the
|
||||
@@ -141,10 +153,10 @@ typedef NS_ENUM(NSInteger,LFLiveCaptureTypeMask) {
|
||||
- (void)stopLive;
|
||||
|
||||
/** support outer input yuv or rgb video(set LFLiveCaptureTypeMask) .*/
|
||||
- (void)pushVideo:(CVPixelBufferRef)pixelBuffer;
|
||||
- (void)pushVideo:(nullable CVPixelBufferRef)pixelBuffer;
|
||||
|
||||
/** support outer input pcm audio(set LFLiveCaptureTypeMask) .*/
|
||||
- (void)pushAudio:(AudioBufferList)audioBufferList;
|
||||
- (void)pushAudio:(nullable NSData*)audioData;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+79
-31
@@ -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"
|
||||
@@ -47,10 +47,10 @@
|
||||
@property (nonatomic, assign, readwrite) LFLiveState state;
|
||||
/// 当前直播type
|
||||
@property (nonatomic, assign, readwrite) LFLiveCaptureTypeMask captureType;
|
||||
|
||||
/// 时间戳锁
|
||||
@property (nonatomic, strong) dispatch_semaphore_t lock;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
/** 时间戳 */
|
||||
@@ -59,16 +59,21 @@
|
||||
|
||||
@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 {
|
||||
- (instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(nullable LFLiveVideoConfiguration *)videoConfiguration {
|
||||
return [self initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration captureType:LFLiveCaptureDefaultMask];
|
||||
}
|
||||
|
||||
@@ -79,15 +84,14 @@
|
||||
_audioConfiguration = audioConfiguration;
|
||||
_videoConfiguration = videoConfiguration;
|
||||
_adaptiveBitrate = NO;
|
||||
_isFirstFrame = YES;
|
||||
_captureType = captureType;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
self.videoCaptureSource.running = NO;
|
||||
self.audioCaptureSource.running = NO;
|
||||
_videoCaptureSource.running = NO;
|
||||
_audioCaptureSource.running = NO;
|
||||
}
|
||||
|
||||
#pragma mark -- CustomMethod
|
||||
@@ -96,7 +100,6 @@
|
||||
_streamInfo = streamInfo;
|
||||
_streamInfo.videoConfiguration = _videoConfiguration;
|
||||
_streamInfo.audioConfiguration = _audioConfiguration;
|
||||
_streamInfo.needDropFrame = (self.captureType & LFLiveCaptureMaskVideo || self.captureType & LFLiveInputMaskVideo) ? YES : NO;//< 有视频执行丢帧算法
|
||||
[self.socket start];
|
||||
}
|
||||
|
||||
@@ -106,42 +109,61 @@
|
||||
self.socket = nil;
|
||||
}
|
||||
|
||||
- (void)pushVideo:(CVPixelBufferRef)pixelBuffer{
|
||||
- (void)pushVideo:(nullable CVPixelBufferRef)pixelBuffer{
|
||||
if(self.captureType & LFLiveInputMaskVideo){
|
||||
if (self.uploading) [self.videoEncoder encodeVideoData:pixelBuffer timeStamp:self.currentTimestamp];
|
||||
if (self.uploading) [self.videoEncoder encodeVideoData:pixelBuffer timeStamp:NOW];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pushAudio:(AudioBufferList)audioBufferList{
|
||||
- (void)pushAudio:(nullable NSData*)audioData{
|
||||
if(self.captureType & LFLiveInputMaskAudio){
|
||||
if (self.uploading) [self.audioEncoder encodeAudioData:audioBufferList timeStamp:self.currentTimestamp];
|
||||
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 {
|
||||
if (self.uploading) [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 CVPixelBufferRef)pixelBuffer {
|
||||
if (self.uploading) [self.videoEncoder encodeVideoData:pixelBuffer timeStamp:self.currentTimestamp];
|
||||
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]; //<上传
|
||||
//<上传 时间戳对齐
|
||||
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]; //<上传
|
||||
//<上传 时间戳对齐
|
||||
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;
|
||||
self.AVAlignment = NO;
|
||||
self.hasCaptureAudio = NO;
|
||||
self.hasKeyFrameVideo = NO;
|
||||
self.relativeTimestamps = 0;
|
||||
self.uploading = YES;
|
||||
}
|
||||
} else if(status == LFLiveStop || status == LFLiveError){
|
||||
@@ -229,6 +251,23 @@
|
||||
[self didChangeValueForKey:@"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;
|
||||
}
|
||||
@@ -297,10 +336,14 @@
|
||||
[self.videoCaptureSource setWarterMarkView:warterMarkView];
|
||||
}
|
||||
|
||||
- (UIView*)warterMarkView{
|
||||
- (nullable UIView*)warterMarkView{
|
||||
return self.videoCaptureSource.warterMarkView;
|
||||
}
|
||||
|
||||
- (nullable UIImage *)currentImage{
|
||||
return self.videoCaptureSource.currentImage;
|
||||
}
|
||||
|
||||
- (LFAudioCapture *)audioCaptureSource {
|
||||
if (!_audioCaptureSource) {
|
||||
if(self.captureType & LFLiveCaptureMaskAudio){
|
||||
@@ -363,18 +406,23 @@
|
||||
return _lock;
|
||||
}
|
||||
|
||||
- (uint64_t)currentTimestamp {
|
||||
- (uint64_t)uploadTimestamp:(uint64_t)captureTimestamp{
|
||||
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
|
||||
uint64_t currentts = 0;
|
||||
if (_isFirstFrame) {
|
||||
_timestamp = NOW;
|
||||
_isFirstFrame = NO;
|
||||
currentts = 0;
|
||||
} else {
|
||||
currentts = NOW - _timestamp;
|
||||
}
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -18,61 +18,52 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
@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
|
||||
|
||||
@implementation LFAudioCapture
|
||||
|
||||
#pragma mark -- LiftCycle
|
||||
- (instancetype)initWithAudioConfiguration:(LFLiveAudioConfiguration *)configuration {
|
||||
if (self = [super init]) {
|
||||
- (instancetype)initWithAudioConfiguration:(LFLiveAudioConfiguration *)configuration{
|
||||
if(self = [super init]){
|
||||
_configuration = configuration;
|
||||
self.isRunning = NO;
|
||||
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:)
|
||||
name:AVAudioSessionRouteChangeNotification
|
||||
object:session];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleInterruption:)
|
||||
name:AVAudioSessionInterruptionNotification
|
||||
object:session];
|
||||
|
||||
NSError *error = nil;
|
||||
|
||||
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
|
||||
|
||||
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
|
||||
|
||||
if (![session setActive:YES error:&error]) {
|
||||
[self handleAudioComponentCreationFailure];
|
||||
}
|
||||
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||
selector: @selector(handleRouteChange:)
|
||||
name: AVAudioSessionRouteChangeNotification
|
||||
object: session];
|
||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||
selector: @selector(handleInterruption:)
|
||||
name: AVAudioSessionInterruptionNotification
|
||||
object: session];
|
||||
|
||||
AudioComponentDescription acd;
|
||||
acd.componentType = kAudioUnitType_Output;
|
||||
acd.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
|
||||
//acd.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
|
||||
acd.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||
acd.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
acd.componentFlags = 0;
|
||||
acd.componentFlagsMask = 0;
|
||||
|
||||
|
||||
self.component = AudioComponentFindNext(NULL, &acd);
|
||||
|
||||
|
||||
OSStatus status = noErr;
|
||||
status = AudioComponentInstanceNew(self.component, &_componetInstance);
|
||||
|
||||
|
||||
if (noErr != status) {
|
||||
[self handleAudioComponentCreationFailure];
|
||||
}
|
||||
|
||||
|
||||
UInt32 flagOne = 1;
|
||||
|
||||
|
||||
AudioUnitSetProperty(self.componetInstance, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &flagOne, sizeof(flagOne));
|
||||
|
||||
|
||||
AudioStreamBasicDescription desc = {0};
|
||||
desc.mSampleRate = _configuration.audioSampleRate;
|
||||
desc.mFormatID = kAudioFormatLinearPCM;
|
||||
@@ -82,22 +73,23 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
desc.mBitsPerChannel = 16;
|
||||
desc.mBytesPerFrame = desc.mBitsPerChannel / 8 * desc.mChannelsPerFrame;
|
||||
desc.mBytesPerPacket = desc.mBytesPerFrame * desc.mFramesPerPacket;
|
||||
|
||||
|
||||
AURenderCallbackStruct cb;
|
||||
cb.inputProcRefCon = (__bridge void *)(self);
|
||||
cb.inputProc = handleInputBuffer;
|
||||
AudioUnitSetProperty(self.componetInstance, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desc, sizeof(desc));
|
||||
AudioUnitSetProperty(self.componetInstance, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 1, &cb, sizeof(cb));
|
||||
|
||||
|
||||
status = AudioUnitInitialize(self.componetInstance);
|
||||
|
||||
|
||||
if (noErr != status) {
|
||||
[self handleAudioComponentCreationFailure];
|
||||
}
|
||||
|
||||
|
||||
[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;
|
||||
@@ -108,6 +100,7 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
|
||||
dispatch_sync(self.taskQueue, ^{
|
||||
if (self.componetInstance) {
|
||||
self.isRunning = NO;
|
||||
AudioOutputUnitStop(self.componetInstance);
|
||||
AudioComponentInstanceDispose(self.componetInstance);
|
||||
self.componetInstance = nil;
|
||||
@@ -124,11 +117,15 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
dispatch_async(self.taskQueue, ^{
|
||||
self.isRunning = YES;
|
||||
NSLog(@"MicrophoneSource: startRunning");
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers error:nil];
|
||||
AudioOutputUnitStart(self.componetInstance);
|
||||
});
|
||||
} else {
|
||||
self.isRunning = NO;
|
||||
dispatch_sync(self.taskQueue, ^{
|
||||
self.isRunning = NO;
|
||||
NSLog(@"MicrophoneSource: stopRunning");
|
||||
AudioOutputUnitStop(self.componetInstance);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +196,7 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
case AVAudioSessionInterruptionOptionShouldResume:
|
||||
if (self.isRunning) {
|
||||
dispatch_async(self.taskQueue, ^{
|
||||
NSLog(@"MicrophoneSource: stopRunning");
|
||||
NSLog(@"MicrophoneSource: startRunning");
|
||||
AudioOutputUnitStart(self.componetInstance);
|
||||
});
|
||||
}
|
||||
@@ -242,15 +239,6 @@ static OSStatus handleInputBuffer(void *inRefCon,
|
||||
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];
|
||||
@@ -259,8 +247,8 @@ static OSStatus handleInputBuffer(void *inRefCon,
|
||||
}
|
||||
|
||||
if (!status) {
|
||||
if (source.delegate && [source.delegate respondsToSelector:@selector(captureOutput:audioBuffer:)]) {
|
||||
[source.delegate captureOutput:source audioBuffer:buffers];
|
||||
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>
|
||||
@@ -57,7 +57,16 @@
|
||||
@property (nonatomic, assign) NSInteger videoFrameRate;
|
||||
|
||||
/*** The warterMarkView control whether the watermark is displayed or not ,if set ni,will remove watermark,otherwise add *.*/
|
||||
@property (nonatomic, strong) UIView *warterMarkView;
|
||||
@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
|
||||
///=============================================================================
|
||||
|
||||
@@ -2,19 +2,26 @@
|
||||
// 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) LFGPUImageBeautyFilter *beautyFilter;
|
||||
@property (nonatomic, strong) GPUImageOutput<GPUImageInput> *filter;
|
||||
@property (nonatomic, strong) GPUImageCropFilter *cropfilter;
|
||||
@property (nonatomic, strong) GPUImageOutput<GPUImageInput> *output;
|
||||
@@ -25,6 +32,8 @@
|
||||
@property (nonatomic, strong) GPUImageUIElement *uiElementInput;
|
||||
@property (nonatomic, strong) UIView *waterMarkContentView;
|
||||
|
||||
@property (nonatomic, strong) GPUImageMovieWriter *movieWriter;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LFVideoCapture
|
||||
@@ -41,6 +50,7 @@
|
||||
[[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;
|
||||
@@ -53,7 +63,11 @@
|
||||
- (void)dealloc {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[self.videoCamera stopCameraCapture];
|
||||
[_videoCamera stopCameraCapture];
|
||||
if(_gpuImageView){
|
||||
[_gpuImageView removeFromSuperview];
|
||||
_gpuImageView = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- Setter Getter
|
||||
@@ -61,24 +75,8 @@
|
||||
- (GPUImageVideoCamera *)videoCamera{
|
||||
if(!_videoCamera){
|
||||
_videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:_configuration.avSessionPreset cameraPosition:AVCaptureDevicePositionFront];
|
||||
UIInterfaceOrientation statusBar = [[UIApplication sharedApplication] statusBarOrientation];
|
||||
if (self.configuration.landscape) {
|
||||
if (statusBar != UIInterfaceOrientationLandscapeLeft && statusBar != UIInterfaceOrientationLandscapeRight) {
|
||||
@throw [NSException exceptionWithName:@"当前设置方向出错" reason:@"LFLiveVideoConfiguration landscape error" userInfo:nil];
|
||||
_videoCamera.outputImageOrientation = UIInterfaceOrientationLandscapeLeft;
|
||||
} else {
|
||||
_videoCamera.outputImageOrientation = statusBar;
|
||||
}
|
||||
} else {
|
||||
if (statusBar != UIInterfaceOrientationPortrait && statusBar != UIInterfaceOrientationPortraitUpsideDown) {
|
||||
@throw [NSException exceptionWithName:@"当前设置方向出错" reason:@"LFLiveVideoConfiguration landscape error" userInfo:nil];
|
||||
_videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
|
||||
} else {
|
||||
_videoCamera.outputImageOrientation = statusBar;
|
||||
}
|
||||
}
|
||||
|
||||
_videoCamera.horizontallyMirrorFrontFacingCamera = YES;
|
||||
_videoCamera.outputImageOrientation = _configuration.outputImageOrientation;
|
||||
_videoCamera.horizontallyMirrorFrontFacingCamera = NO;
|
||||
_videoCamera.horizontallyMirrorRearFacingCamera = NO;
|
||||
_videoCamera.frameRate = (int32_t)_configuration.videoFrameRate;
|
||||
}
|
||||
@@ -92,10 +90,12 @@
|
||||
if (!_running) {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
[self.videoCamera stopCameraCapture];
|
||||
if(self.saveLocalVideo) [self.movieWriter finishRecording];
|
||||
} else {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
||||
[self reloadFilter];
|
||||
[self.videoCamera startCameraCapture];
|
||||
if(self.saveLocalVideo) [self.movieWriter startRecording];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,8 +110,10 @@
|
||||
}
|
||||
|
||||
- (void)setCaptureDevicePosition:(AVCaptureDevicePosition)captureDevicePosition {
|
||||
if(captureDevicePosition == self.videoCamera.cameraPosition) return;
|
||||
[self.videoCamera rotateCamera];
|
||||
self.videoCamera.frameRate = (int32_t)_configuration.videoFrameRate;
|
||||
[self reloadMirror];
|
||||
}
|
||||
|
||||
- (AVCaptureDevicePosition)captureDevicePosition {
|
||||
@@ -158,7 +160,6 @@
|
||||
|
||||
- (void)setMirror:(BOOL)mirror {
|
||||
_mirror = mirror;
|
||||
self.videoCamera.horizontallyMirrorFrontFacingCamera = mirror;
|
||||
}
|
||||
|
||||
- (void)setBeautyFace:(BOOL)beautyFace{
|
||||
@@ -248,6 +249,24 @@
|
||||
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 {
|
||||
__weak typeof(self) _self = self;
|
||||
@@ -260,7 +279,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)reloadFilter{
|
||||
[self.filter removeAllTargets];
|
||||
[self.blendFilter removeAllTargets];
|
||||
@@ -272,13 +290,16 @@
|
||||
if (self.beautyFace) {
|
||||
self.output = [[LFGPUImageEmptyFilter alloc] init];
|
||||
self.filter = [[LFGPUImageBeautyFilter alloc] init];
|
||||
self.beautyFilter = self.filter;
|
||||
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);
|
||||
@@ -294,11 +315,13 @@
|
||||
[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];
|
||||
@@ -306,6 +329,7 @@
|
||||
[self.blendFilter forceProcessingAtSize:self.configuration.videoSize];
|
||||
[self.uiElementInput forceProcessingAtSize:self.configuration.videoSize];
|
||||
|
||||
|
||||
//< 输出数据
|
||||
__weak typeof(self) _self = self;
|
||||
[self.output setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
|
||||
@@ -314,6 +338,14 @@
|
||||
|
||||
}
|
||||
|
||||
- (void)reloadMirror{
|
||||
if(self.mirror && self.captureDevicePosition == AVCaptureDevicePositionFront){
|
||||
self.videoCamera.horizontallyMirrorFrontFacingCamera = YES;
|
||||
}else{
|
||||
self.videoCamera.horizontallyMirrorFrontFacingCamera = NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Notification
|
||||
|
||||
- (void)willEnterBackground:(NSNotification *)notification {
|
||||
@@ -332,17 +364,20 @@
|
||||
- (void)statusBarChanged:(NSNotification *)notification {
|
||||
NSLog(@"UIApplicationWillChangeStatusBarOrientationNotification. UserInfo: %@", notification.userInfo);
|
||||
UIInterfaceOrientation statusBar = [[UIApplication sharedApplication] statusBarOrientation];
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,13 @@
|
||||
#import <AVFoundation/AVAssetWriterInput.h>
|
||||
#import <AVFoundation/AVMediaFormat.h>
|
||||
#import <AVFoundation/AVVideoSettings.h>
|
||||
#import "sys/stat.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);
|
||||
|
||||
@@ -26,7 +29,6 @@ typedef int (^param_handler_t)(NSData *params);
|
||||
|
||||
- (void)encodeWithBlock:(encoder_handler_t)block onParams:(param_handler_t)paramsHandler;
|
||||
- (void)encodeFrame:(CMSampleBufferRef)sampleBuffer;
|
||||
- (void)encodePixelBuffer:(CVPixelBufferRef)pixelBuffer pts:(CMTime)pts;
|
||||
- (NSData *)getConfigData;
|
||||
- (void)shutdown;
|
||||
|
||||
|
||||
@@ -91,12 +91,12 @@ static unsigned int to_host(unsigned char *p){
|
||||
_width = width;
|
||||
_bitrate = bitrate;
|
||||
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"params.mp4"];
|
||||
_headerWriter = [LFVideoEncoder encoderForPath:path Height:height andWidth:width bitrate:self.bitrate];
|
||||
_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:self.bitrate];
|
||||
_writer = [LFVideoEncoder encoderForPath:[self makeFilename] Height:height andWidth:width bitrate:(int)self.bitrate];
|
||||
|
||||
[self addObserver:self forKeyPath:NSStringFromSelector(@selector(bitrate)) options:0 context:AVEncoderContext];
|
||||
}
|
||||
@@ -123,7 +123,7 @@ static unsigned int to_host(unsigned char *p){
|
||||
NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];
|
||||
struct stat s;
|
||||
fstat([file fileDescriptor], &s);
|
||||
LFMP4Atom *movie = [LFMP4Atom atomAt:0 size:s.st_size type:(OSType)('file') inFile:file];
|
||||
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) {
|
||||
@@ -164,7 +164,7 @@ static unsigned int to_host(unsigned char *p){
|
||||
LFMP4Atom *esd = [avc1 childOfType:(OSType)('avcC') startAt:78];
|
||||
if (esd != nil) {
|
||||
// this is the avcC record that we are looking for
|
||||
_avcC = [esd readAt:0 size:esd.length];
|
||||
_avcC = [esd readAt:0 size:(int)esd.length];
|
||||
if (_avcC != nil) {
|
||||
// extract size of length field
|
||||
unsigned char *p = (unsigned char *)[_avcC bytes];
|
||||
@@ -236,7 +236,7 @@ static unsigned int to_host(unsigned char *p){
|
||||
_currentFile = 1;
|
||||
}
|
||||
//NSLog(@"Swap to file %d", _currentFile);
|
||||
_writer = [LFVideoEncoder encoderForPath:[self makeFilename] Height:_height andWidth:_width bitrate:self.bitrate];
|
||||
_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
|
||||
@@ -319,7 +319,7 @@ static unsigned int to_host(unsigned char *p){
|
||||
// called whenever there is more data to read in the main encoder output file.
|
||||
struct stat s;
|
||||
fstat([_inputFile fileDescriptor], &s);
|
||||
int cReady = s.st_size - [_inputFile offsetInFile];
|
||||
int cReady = (int)(s.st_size - [_inputFile offsetInFile]);
|
||||
|
||||
// locate the mdat atom if needed
|
||||
while (!_foundMDAT && (cReady > 8)) {
|
||||
@@ -385,7 +385,7 @@ static unsigned int to_host(unsigned char *p){
|
||||
int naltype = pNal[0] & 0x1f;
|
||||
|
||||
if (_pendingNALU) {
|
||||
LFNALUnit nal(pNal, [nalu length]);
|
||||
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.
|
||||
@@ -397,7 +397,7 @@ static unsigned int to_host(unsigned char *p){
|
||||
bNew = YES;
|
||||
} else if ((naltype >= 1) && (naltype <= 5)) {
|
||||
nal.Skip(8);
|
||||
int first_mb = nal.GetUE();
|
||||
int first_mb = (int)nal.GetUE();
|
||||
if (first_mb == 0) {
|
||||
bNew = YES;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ static unsigned int to_host(unsigned char *p){
|
||||
int64_t offset = _nextChild + cHeader;
|
||||
_nextChild += len;
|
||||
len -= cHeader;
|
||||
return [LFMP4Atom atomAt:offset+_offset size:len type:fourcc inFile:_file];
|
||||
return [LFMP4Atom atomAt:offset+_offset size:(int)len type:fourcc inFile:_file];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ ScalingList(int size, LFNALUnit *pnalu){
|
||||
long delta = pnalu->GetSE();
|
||||
nextScale = (lastScale + delta + 256) %256;
|
||||
}
|
||||
int scaling_list_j = (nextScale == 0) ? lastScale : nextScale;
|
||||
int scaling_list_j = (nextScale == 0) ? (int)lastScale : (int)nextScale;
|
||||
lastScale = scaling_list_j;
|
||||
}
|
||||
}
|
||||
@@ -237,21 +237,21 @@ LFSeqParamSet::Parse(LFNALUnit *pnalu){
|
||||
// to get through to the ones we want
|
||||
pnalu->ResetBitstream();
|
||||
pnalu->Skip(8); // type
|
||||
m_Profile = pnalu->GetWord(8);
|
||||
m_Profile =(int) pnalu->GetWord(8);
|
||||
m_Compatibility = (BYTE)pnalu->GetWord(8);
|
||||
m_Level = 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 = pnalu->GetUE();
|
||||
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 = pnalu->GetBit();
|
||||
int seq_scaling_matrix_present = (int)pnalu->GetBit();
|
||||
if (seq_scaling_matrix_present) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (pnalu->GetBit()) {
|
||||
@@ -265,16 +265,16 @@ LFSeqParamSet::Parse(LFNALUnit *pnalu){
|
||||
}
|
||||
}
|
||||
|
||||
int log2_frame_minus4 = pnalu->GetUE();
|
||||
int log2_frame_minus4 = (int)pnalu->GetUE();
|
||||
m_FrameBits = log2_frame_minus4 + 4;
|
||||
int POCtype = pnalu->GetUE();
|
||||
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 = pnalu->GetUE();
|
||||
int num_ref_in_cycle = (int)pnalu->GetUE();
|
||||
for (int i = 0; i < num_ref_in_cycle; i++) {
|
||||
/*int sf_offset =*/ pnalu->GetSE();
|
||||
}
|
||||
@@ -286,8 +286,8 @@ LFSeqParamSet::Parse(LFNALUnit *pnalu){
|
||||
/*int num_ref_frames =*/ pnalu->GetUE();
|
||||
/*int gaps_allowed =*/ pnalu->GetBit();
|
||||
|
||||
int mbs_width = pnalu->GetUE();
|
||||
int mbs_height = pnalu->GetUE();
|
||||
int mbs_width = (int)pnalu->GetUE();
|
||||
int mbs_height = (int)pnalu->GetUE();
|
||||
m_cx = (mbs_width+1) * 16;
|
||||
m_cy = (mbs_height+1) * 16;
|
||||
|
||||
@@ -359,7 +359,7 @@ LFSliceHeader::Parse(LFNALUnit *pnalu){
|
||||
pnalu->GetUE(); // slice type
|
||||
pnalu->GetUE(); // pic param set id
|
||||
|
||||
m_framenum = pnalu->GetWord(m_nBitsFrame);
|
||||
m_framenum = (int)pnalu->GetWord(m_nBitsFrame);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "AVFoundation/AVAssetWriter.h"
|
||||
#import "AVFoundation/AVAssetWriterInput.h"
|
||||
#import "AVFoundation/AVMediaFormat.h"
|
||||
#import "AVFoundation/AVVideoSettings.h"
|
||||
#import <AVFoundation/AVAssetWriter.h>
|
||||
#import <AVFoundation/AVAssetWriterInput.h>
|
||||
#import <AVFoundation/AVMediaFormat.h>
|
||||
#import <AVFoundation/AVVideoSettings.h>
|
||||
|
||||
@interface LFVideoEncoder : NSObject
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# GDCL Source Code License
|
||||
|
||||
Last updated: 20th February 2013
|
||||
|
||||
**License Agreement for Source Code provided by GDCL**
|
||||
|
||||
This software is supplied to you by Geraint Davies Consulting Ltd ('GDCL') in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject to these terms, GDCL grants you a personal, non-exclusive license, to use, reproduce, modify and redistribute the software, with or without modifications, in source and/or binary forms; provided that if you redistribute the software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the software, and that in all cases attribution of GDCL as the original author of the source code shall be included in all such resulting software products or distributions.
|
||||
|
||||
Neither the name, trademarks, service marks or logos of Geraint Davies or GDCL may be used to endorse or promote products derived from the software without specific prior written permission from GDCL. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by GDCL herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the software may be incorporated.
|
||||
|
||||
The software is provided by GDCL on an "AS IS" basis. GDCL MAKE NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL GDCL BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF GDCL HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -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,6 +11,8 @@
|
||||
#import "LFAudioFrame.h"
|
||||
#import "LFLiveAudioConfiguration.h"
|
||||
|
||||
|
||||
|
||||
@protocol LFAudioEncoding;
|
||||
/// 编码器编码后回调
|
||||
@protocol LFAudioEncodingDelegate <NSObject>
|
||||
@@ -21,7 +23,7 @@
|
||||
/// 编码器抽象的接口
|
||||
@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;
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
// LFH264VideoEncoder
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by feng on 7/5/16.
|
||||
// Copyright (c) 2014 zhanqi.tv. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFVideoEncoding.h"
|
||||
|
||||
@interface LFH264VideoEncoder : NSObject <LFVideoEncoding> {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFH264VideoEncoder
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by feng on 7/5/16.
|
||||
// Copyright (c) 2014 zhanqi.tv. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <CoreMedia/CoreMedia.h>
|
||||
@@ -60,7 +60,7 @@
|
||||
[self initForFilePath];
|
||||
#endif
|
||||
|
||||
_encoder = [LFAVEncoder encoderForHeight:_configuration.videoSize.height andWidth:_configuration.videoSize.width bitrate:_configuration.videoBitRate];
|
||||
_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;
|
||||
@@ -85,7 +85,7 @@
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
LFavcCHeader avcC((const BYTE*)[config bytes], [config length]);
|
||||
LFavcCHeader avcC((const BYTE*)[config bytes], (int)[config length]);
|
||||
LFSeqParamSet seqParams;
|
||||
seqParams.Parse(avcC.sps());
|
||||
|
||||
@@ -107,6 +107,8 @@
|
||||
[_videoSPSandPPS appendData:ppsData];
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void)setVideoBitRate:(NSInteger)videoBitRate{
|
||||
_currentVideoBitRate = videoBitRate;
|
||||
_encoder.bitrate = _currentVideoBitRate;
|
||||
@@ -162,7 +164,7 @@
|
||||
[totalFrames addObjectsFromArray:frames];
|
||||
|
||||
NSMutableData *aggregateFrameData = [NSMutableData data];
|
||||
BOOL hasKeyframe = NO;
|
||||
//BOOL hasKeyframe = NO;
|
||||
|
||||
for (NSData *data in totalFrames) {
|
||||
unsigned char* pNal = (unsigned char*)[data bytes];
|
||||
@@ -174,7 +176,7 @@
|
||||
_sei = [NSMutableData dataWithData:data];
|
||||
continue;
|
||||
} else if (naltype == 5) { // IDR
|
||||
hasKeyframe = YES;
|
||||
//hasKeyframe = YES;
|
||||
NSMutableData *IDRData = [NSMutableData dataWithData:_videoSPSandPPS];
|
||||
if (_sei) {
|
||||
[IDRData appendData:_naluStartCode];
|
||||
@@ -246,25 +248,16 @@
|
||||
}
|
||||
|
||||
- (void)initForFilePath {
|
||||
char *path = [self GetFilePathByfileName:"IOSCamDemo.h264"];
|
||||
NSLog(@"%s", path);
|
||||
self->fp = fopen(path, "wb");
|
||||
NSString *path = [self GetFilePathByfileName:@"IOSCamDemo.h264"];
|
||||
NSLog(@"%@", path);
|
||||
self->fp = fopen([path cStringUsingEncoding:NSUTF8StringEncoding], "wb");
|
||||
}
|
||||
|
||||
- (char *)GetFilePathByfileName:(char *)filename {
|
||||
- (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 @@
|
||||
// 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,16 +23,31 @@
|
||||
|
||||
@implementation LFHardwareAudioEncoder
|
||||
|
||||
- (instancetype)initWithAudioStreamConfiguration:(LFLiveAudioConfiguration *)configuration {
|
||||
- (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);
|
||||
if (leftBuf) free(leftBuf);
|
||||
}
|
||||
|
||||
#pragma mark -- LFAudioEncoder
|
||||
@@ -36,29 +55,67 @@
|
||||
_aacDeleage = delegate;
|
||||
}
|
||||
|
||||
- (void)encodeAudioData:(AudioBufferList)inBufferList timeStamp:(uint64_t)timeStamp {
|
||||
- (void)encodeAudioData:(nullable NSData*)audioData timeStamp:(uint64_t)timeStamp {
|
||||
if (![self createAudioConvert]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aacBuf) {
|
||||
aacBuf = malloc(inBufferList.mBuffers[0].mDataByteSize);
|
||||
|
||||
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)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 = inBufferList.mBuffers[0].mNumberChannels;
|
||||
outBufferList.mBuffers[0].mDataByteSize = inBufferList.mBuffers[0].mDataByteSize; // 设置缓冲区大小
|
||||
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, &inBufferList, &outputDataPacketSize, &outBufferList, NULL) != noErr) {
|
||||
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];
|
||||
@@ -66,10 +123,17 @@
|
||||
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
|
||||
@@ -77,7 +141,7 @@
|
||||
if (m_converter != nil) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
AudioStreamBasicDescription inputFormat = {0};
|
||||
inputFormat.mSampleRate = _configuration.audioSampleRate;
|
||||
inputFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
@@ -87,14 +151,14 @@
|
||||
inputFormat.mBitsPerChannel = 16;
|
||||
inputFormat.mBytesPerFrame = inputFormat.mBitsPerChannel / 8 * inputFormat.mChannelsPerFrame;
|
||||
inputFormat.mBytesPerPacket = inputFormat.mBytesPerFrame * inputFormat.mFramesPerPacket;
|
||||
|
||||
|
||||
AudioStreamBasicDescription outputFormat; // 这里开始是输出音频格式
|
||||
memset(&outputFormat, 0, sizeof(outputFormat));
|
||||
outputFormat.mSampleRate = inputFormat.mSampleRate; // 采样率保持一致
|
||||
outputFormat.mFormatID = kAudioFormatMPEG4AAC; // AAC编码 kAudioFormatMPEG4AAC kAudioFormatMPEG4AAC_HE_V2
|
||||
outputFormat.mChannelsPerFrame = (UInt32)_configuration.numberOfChannels;;
|
||||
outputFormat.mFramesPerPacket = 1024; // AAC一帧是1024个字节
|
||||
|
||||
|
||||
const OSType subtype = kAudioFormatMPEG4AAC;
|
||||
AudioClassDescription requestedCodecs[2] = {
|
||||
{
|
||||
@@ -108,35 +172,19 @@
|
||||
kAppleHardwareAudioCodecManufacturer
|
||||
}
|
||||
};
|
||||
OSStatus result = AudioConverterNewSpecific(&inputFormat, &outputFormat, 2, requestedCodecs, &m_converter);
|
||||
if (result != noErr) return NO;
|
||||
|
||||
|
||||
OSStatus result = AudioConverterNewSpecific(&inputFormat, &outputFormat, 2, requestedCodecs, &m_converter);;
|
||||
UInt32 outputBitrate = _configuration.audioBitrate;
|
||||
UInt32 propSize = sizeof(outputBitrate);
|
||||
|
||||
|
||||
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>
|
||||
@@ -147,6 +195,8 @@ OSStatus inputDataProc(AudioConverterRef inConverter, UInt32 *ioNumberDataPacket
|
||||
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
|
||||
@@ -162,7 +212,7 @@ OSStatus inputDataProc(AudioConverterRef inConverter, UInt32 *ioNumberDataPacket
|
||||
// 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
|
||||
@@ -177,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>
|
||||
|
||||
@@ -20,8 +19,8 @@
|
||||
|
||||
@property (nonatomic, strong) LFLiveVideoConfiguration *configuration;
|
||||
@property (nonatomic, weak) id<LFVideoEncodingDelegate> h264Delegate;
|
||||
@property (nonatomic) BOOL isBackGround;
|
||||
@property (nonatomic) NSInteger currentVideoBitRate;
|
||||
@property (nonatomic) BOOL isBackGround;
|
||||
|
||||
@end
|
||||
|
||||
@@ -32,20 +31,19 @@
|
||||
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 {
|
||||
- (void)resetCompressionSession {
|
||||
if (compressionSession) {
|
||||
VTCompressionSessionCompleteFrames(compressionSession, kCMTimeInvalid);
|
||||
|
||||
@@ -61,7 +59,7 @@
|
||||
|
||||
_currentVideoBitRate = _configuration.videoBitRate;
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_MaxKeyFrameInterval, (__bridge CFTypeRef)@(_configuration.videoMaxKeyframeInterval));
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, (__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)];
|
||||
@@ -75,7 +73,7 @@
|
||||
}
|
||||
|
||||
- (void)setVideoBitRate:(NSInteger)videoBitRate {
|
||||
if (_isBackGround) return;
|
||||
if(_isBackGround) return;
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_AverageBitRate, (__bridge CFTypeRef)@(videoBitRate));
|
||||
NSArray *limit = @[@(videoBitRate * 1.5/8), @(1)];
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_DataRateLimits, (__bridge CFArrayRef)limit);
|
||||
@@ -99,10 +97,9 @@
|
||||
|
||||
#pragma mark -- LFVideoEncoder
|
||||
- (void)encodeVideoData:(CVPixelBufferRef)pixelBuffer timeStamp:(uint64_t)timeStamp {
|
||||
if (_isBackGround) return;
|
||||
|
||||
if(_isBackGround) return;
|
||||
frameCount++;
|
||||
CMTime presentationTimeStamp = CMTimeMake(frameCount, 1000);
|
||||
CMTime presentationTimeStamp = CMTimeMake(frameCount, (int32_t)_configuration.videoFrameRate);
|
||||
VTEncodeInfoFlags flags;
|
||||
CMTime duration = CMTimeMake(1, (int32_t)_configuration.videoFrameRate);
|
||||
|
||||
@@ -112,7 +109,10 @@
|
||||
}
|
||||
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 {
|
||||
@@ -123,13 +123,13 @@
|
||||
_h264Delegate = delegate;
|
||||
}
|
||||
|
||||
#pragma mark -- NSNotification
|
||||
- (void)willEnterBackground:(NSNotification *)notification {
|
||||
#pragma mark -- Notification
|
||||
- (void)willEnterBackground:(NSNotification*)notification{
|
||||
_isBackGround = YES;
|
||||
}
|
||||
|
||||
- (void)willEnterForeground:(NSNotification *)notification {
|
||||
[self initCompressionSession];
|
||||
- (void)willEnterForeground:(NSNotification*)notification{
|
||||
[self resetCompressionSession];
|
||||
_isBackGround = NO;
|
||||
}
|
||||
|
||||
@@ -226,25 +226,16 @@ static void VideoCompressonOutputCallback(void *VTref, void *VTFrameRef, OSStatu
|
||||
}
|
||||
|
||||
- (void)initForFilePath {
|
||||
char *path = [self GetFilePathByfileName:"IOSCamDemo_HW.h264"];
|
||||
NSLog(@"%s", path);
|
||||
self->fp = fopen(path, "wb");
|
||||
NSString *path = [self GetFilePathByfileName:@"IOSCamDemo.h264"];
|
||||
NSLog(@"%@", path);
|
||||
self->fp = fopen([path cStringUsingEncoding:NSUTF8StringEncoding], "wb");
|
||||
}
|
||||
|
||||
- (char *)GetFilePathByfileName:(char *)filename {
|
||||
- (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>
|
||||
@@ -21,11 +21,10 @@
|
||||
@protocol LFVideoEncoding <NSObject>
|
||||
@required
|
||||
- (void)encodeVideoData:(nullable CVPixelBufferRef)pixelBuffer timeStamp:(uint64_t)timeStamp;
|
||||
- (void)stopEncoder;
|
||||
@optional
|
||||
@property (nonatomic, assign) NSInteger videoBitRate;
|
||||
- (nullable instancetype)initWithVideoStreamConfiguration:(nullable LFLiveVideoConfiguration *)configuration;
|
||||
- (void)setDelegate:(nullable id<LFVideoEncodingDelegate>)delegate;
|
||||
|
||||
- (void)stopEncoder;
|
||||
@end
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
// 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>
|
||||
|
||||
/// 音频码率
|
||||
/// 音频码率 (默认96Kbps)
|
||||
typedef NS_ENUM (NSUInteger, LFLiveAudioBitRate) {
|
||||
/// 32Kbps 音频码率
|
||||
LFLiveAudioBitRate_32Kbps = 32000,
|
||||
@@ -18,32 +18,34 @@ typedef NS_ENUM (NSUInteger, LFLiveAudioBitRate) {
|
||||
LFLiveAudioBitRate_96Kbps = 96000,
|
||||
/// 128Kbps 音频码率
|
||||
LFLiveAudioBitRate_128Kbps = 128000,
|
||||
/// 默认音频码率,默认为 64Kbps
|
||||
LFLiveAudioBitRate_Default = LFLiveAudioBitRate_64Kbps
|
||||
/// 默认音频码率,默认为 96Kbps
|
||||
LFLiveAudioBitRate_Default = LFLiveAudioBitRate_96Kbps
|
||||
};
|
||||
|
||||
/// 采样率 (默认44.1Hz iphoneg6以上48Hz)
|
||||
/// 音频采样率 (默认44.1KHz)
|
||||
typedef NS_ENUM (NSUInteger, LFLiveAudioSampleRate){
|
||||
/// 44.1Hz 采样率
|
||||
/// 16KHz 采样率
|
||||
LFLiveAudioSampleRate_16000Hz = 16000,
|
||||
/// 44.1KHz 采样率
|
||||
LFLiveAudioSampleRate_44100Hz = 44100,
|
||||
/// 48Hz 采样率
|
||||
/// 48KHz 采样率
|
||||
LFLiveAudioSampleRate_48000Hz = 48000,
|
||||
/// 默认音频码率,默认为 64Kbps
|
||||
/// 默认音频采样率,默认为 44.1KHz
|
||||
LFLiveAudioSampleRate_Default = LFLiveAudioSampleRate_44100Hz
|
||||
};
|
||||
|
||||
/// Audio Live quality(音频质量)
|
||||
typedef NS_ENUM (NSUInteger, LFLiveAudioQuality){
|
||||
/// 高音频质量 audio sample rate: 44MHz(默认44.1Hz iphoneg6以上48Hz), audio bitrate: 32Kbps
|
||||
/// 低音频质量 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: 44.1KHz audio bitrate: 96Kbps
|
||||
LFLiveAudioQuality_Medium = 1,
|
||||
/// 高音频质量 audio sample rate: 44MHz(默认44.1Hz iphoneg6以上48Hz), audio bitrate: 96Kbps
|
||||
/// 高音频质量 audio sample rate: 44.1MHz audio bitrate: 128Kbps
|
||||
LFLiveAudioQuality_High = 2,
|
||||
/// 高音频质量 audio sample rate: 44MHz(默认44.1Hz iphoneg6以上48Hz), audio bitrate: 128Kbps
|
||||
/// 超高音频质量 audio sample rate: 48KHz, audio bitrate: 128Kbps
|
||||
LFLiveAudioQuality_VeryHigh = 3,
|
||||
/// 默认音频质量 audio sample rate: 44MHz(默认44.1Hz iphoneg6以上48Hz), audio bitrate: 64Kbps
|
||||
LFLiveAudioQuality_Default = LFLiveAudioQuality_Medium
|
||||
/// 默认音频质量 audio sample rate: 44.1KHz, audio bitrate: 96Kbps
|
||||
LFLiveAudioQuality_Default = LFLiveAudioQuality_High
|
||||
};
|
||||
|
||||
@interface LFLiveAudioConfiguration : NSObject<NSCoding, NSCopying>
|
||||
@@ -61,9 +63,11 @@ typedef NS_ENUM (NSUInteger, LFLiveAudioQuality){
|
||||
@property (nonatomic, assign) NSUInteger numberOfChannels;
|
||||
/// 采样率
|
||||
@property (nonatomic, assign) LFLiveAudioSampleRate audioSampleRate;
|
||||
// 码率
|
||||
/// 码率
|
||||
@property (nonatomic, assign) LFLiveAudioBitRate audioBitrate;
|
||||
/// flv编码音频头 44100 为0x12 0x10
|
||||
@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"
|
||||
@@ -21,24 +21,32 @@
|
||||
LFLiveAudioConfiguration *audioConfig = [LFLiveAudioConfiguration new];
|
||||
audioConfig.numberOfChannels = 2;
|
||||
switch (audioQuality) {
|
||||
case LFLiveAudioQuality_Default: {
|
||||
audioConfig.audioBitrate = LFLiveAudioBitRate_64Kbps;
|
||||
}
|
||||
break;
|
||||
case LFLiveAudioQuality_Low: {
|
||||
audioConfig.audioBitrate = LFLiveAudioBitRate_32Kbps;
|
||||
audioConfig.audioBitrate = audioConfig.numberOfChannels == 1 ? LFLiveAudioBitRate_32Kbps : LFLiveAudioBitRate_64Kbps;
|
||||
audioConfig.audioSampleRate = LFLiveAudioSampleRate_16000Hz;
|
||||
}
|
||||
case LFLiveAudioQuality_High: {
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
audioConfig.audioSampleRate = [self.class isNewThaniPhone6] ? LFLiveAudioSampleRate_48000Hz : LFLiveAudioSampleRate_44100Hz;
|
||||
|
||||
return audioConfig;
|
||||
}
|
||||
@@ -58,17 +66,21 @@
|
||||
- (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 {
|
||||
_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 = 0;
|
||||
@@ -118,57 +130,6 @@
|
||||
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"];
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// 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>
|
||||
@@ -51,7 +51,7 @@ 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
|
||||
///=============================================================================
|
||||
@@ -64,7 +64,10 @@ typedef NS_ENUM (NSUInteger, LFLiveVideoQuality){
|
||||
@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;
|
||||
@@ -93,4 +96,7 @@ typedef NS_ENUM (NSUInteger, LFLiveVideoQuality){
|
||||
///< ≈sde3分辨率
|
||||
@property (nonatomic, assign, readonly) NSString *avSessionPreset;
|
||||
|
||||
///< 是否是横屏
|
||||
@property (nonatomic, assign, readonly) BOOL landscape;
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// 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"
|
||||
@@ -20,11 +20,11 @@
|
||||
}
|
||||
|
||||
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality {
|
||||
LFLiveVideoConfiguration *configuration = [LFLiveVideoConfiguration defaultConfigurationForQuality:videoQuality landscape:NO];
|
||||
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:{
|
||||
@@ -131,9 +131,9 @@
|
||||
}
|
||||
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 {
|
||||
configuration.videoSize = CGSizeMake(size.width, size.height);
|
||||
@@ -166,6 +166,10 @@
|
||||
return avSessionPreset;
|
||||
}
|
||||
|
||||
- (BOOL)landscape{
|
||||
return (self.outputImageOrientation == UIInterfaceOrientationLandscapeLeft || self.outputImageOrientation == UIInterfaceOrientationLandscapeRight) ? YES : NO;
|
||||
}
|
||||
|
||||
- (CGSize)videoSize{
|
||||
if(_videoSizeRespectingAspectRatio){
|
||||
return self.aspectRatioVideoSize;
|
||||
@@ -249,7 +253,7 @@
|
||||
break;
|
||||
}
|
||||
|
||||
if(self.landscape){
|
||||
if (self.landscape){
|
||||
return CGSizeMake(videoSize.height, videoSize.width);
|
||||
}
|
||||
return videoSize;
|
||||
@@ -275,7 +279,8 @@
|
||||
[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"];
|
||||
}
|
||||
|
||||
@@ -290,7 +295,8 @@
|
||||
_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;
|
||||
}
|
||||
@@ -307,7 +313,8 @@
|
||||
@(self.videoMinBitRate),
|
||||
self.avSessionPreset,
|
||||
@(self.sessionPreset),
|
||||
@(self.landscape),
|
||||
@(self.outputImageOrientation),
|
||||
@(self.autorotate),
|
||||
@(self.videoSizeRespectingAspectRatio)];
|
||||
|
||||
for (NSObject *value in values) {
|
||||
@@ -333,7 +340,8 @@
|
||||
object.videoMinBitRate == self.videoMinBitRate &&
|
||||
[object.avSessionPreset isEqualToString:self.avSessionPreset] &&
|
||||
object.sessionPreset == self.sessionPreset &&
|
||||
object.landscape == self.landscape &&
|
||||
object.outputImageOrientation == self.outputImageOrientation &&
|
||||
object.autorotate == self.autorotate &&
|
||||
object.videoSizeRespectingAspectRatio == self.videoSizeRespectingAspectRatio;
|
||||
}
|
||||
}
|
||||
@@ -357,7 +365,8 @@
|
||||
[desc appendFormat:@" videoMinBitRate:%zi", self.videoMinBitRate];
|
||||
[desc appendFormat:@" avSessionPreset:%@", self.avSessionPreset];
|
||||
[desc appendFormat:@" sessionPreset:%zi", self.sessionPreset];
|
||||
[desc appendFormat:@" landscape:%zi", self.landscape];
|
||||
[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 {
|
||||
}
|
||||
|
||||
@@ -238,7 +238,6 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
|
||||
}
|
||||
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex {
|
||||
CGSize oldInputSize = inputTextureSize;
|
||||
[super setInputSize:newSize atIndex:textureIndex];
|
||||
inputTextureSize = newSize;
|
||||
|
||||
|
||||
@@ -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,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>
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
// 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"
|
||||
|
||||
@implementation LFLiveDebug
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"丢掉的帧数:%ld 总帧数:%ld 上次的音频捕获个数:%d 上次的视频捕获个数:%d 未发送个数:%ld 总流量:%0.f",_dropFrame,_totalFrame,_currentCapturedAudioCount,_currentCapturedVideoCount,_unSendCount,_dataFlow];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
// 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){
|
||||
/// 准备
|
||||
@@ -21,7 +23,9 @@ typedef NS_ENUM (NSUInteger, LFLiveState){
|
||||
/// 已断开
|
||||
LFLiveStop = 3,
|
||||
/// 连接出错
|
||||
LFLiveError = 4
|
||||
LFLiveError = 4,
|
||||
/// 正在刷新
|
||||
LFLiveRefresh = 5
|
||||
};
|
||||
|
||||
typedef NS_ENUM (NSUInteger, LFLiveSocketErrorCode) {
|
||||
@@ -45,7 +49,5 @@ typedef NS_ENUM (NSUInteger, LFLiveSocketErrorCode) {
|
||||
@property (nonatomic, strong) LFLiveAudioConfiguration *audioConfiguration;
|
||||
///视频配置
|
||||
@property (nonatomic, strong) LFLiveVideoConfiguration *videoConfiguration;
|
||||
///是否丢帧
|
||||
@property (nonatomic, assign) BOOL needDropFrame;
|
||||
|
||||
@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"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// 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"
|
||||
|
||||
@@ -2,14 +2,19 @@
|
||||
// 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 "rtmp.h"
|
||||
|
||||
static const NSInteger RetryTimesBreaken = 20; ///< 重连1分钟 3秒一次 一共20次
|
||||
#if __has_include(<pili-librtmp/rtmp.h>)
|
||||
#import <pili-librtmp/rtmp.h>
|
||||
#else
|
||||
#import "rtmp.h"
|
||||
#endif
|
||||
|
||||
static const NSInteger RetryTimesBreaken = 5; ///< 重连1分钟 3秒一次 一共20次
|
||||
static const NSInteger RetryTimesMargin = 3;
|
||||
|
||||
|
||||
@@ -21,7 +26,7 @@ static const NSInteger RetryTimesMargin = 3;
|
||||
#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.8.0");
|
||||
static const AVal av_SDKVersion = AVC("LFLiveKit 2.4.0");
|
||||
SAVC(onMetaData);
|
||||
SAVC(duration);
|
||||
SAVC(width);
|
||||
@@ -33,10 +38,10 @@ 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);
|
||||
@@ -105,12 +110,24 @@ SAVC(mp4a);
|
||||
self.debugInfo.streamId = self.stream.streamId;
|
||||
self.debugInfo.uploadUrl = self.stream.url;
|
||||
self.debugInfo.isRtmp = YES;
|
||||
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(self.rtmpSendQueue, ^{
|
||||
[self _stop];
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -124,12 +141,12 @@ SAVC(mp4a);
|
||||
_rtmp = NULL;
|
||||
}
|
||||
[self clean];
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
||||
}
|
||||
|
||||
- (void)sendFrame:(LFFrame *)frame {
|
||||
if (!frame) return;
|
||||
[self.buffer appendObject:frame];
|
||||
|
||||
if(!self.isSending){
|
||||
[self sendFrame];
|
||||
}
|
||||
@@ -141,74 +158,75 @@ SAVC(mp4a);
|
||||
|
||||
#pragma mark -- CustomMethod
|
||||
- (void)sendFrame {
|
||||
__weak typeof(self) _self = self;
|
||||
dispatch_async(self.rtmpSendQueue, ^{
|
||||
if (!self.isSending && self.buffer.list.count > 0) {
|
||||
self.isSending = YES;
|
||||
if (!_self.isSending && _self.buffer.list.count > 0) {
|
||||
_self.isSending = YES;
|
||||
|
||||
if (!_isConnected || _isReconnecting || _isConnecting || !_rtmp){
|
||||
self.isSending = NO;
|
||||
if (!_self.isConnected || _self.isReconnecting || _self.isConnecting || !_rtmp){
|
||||
_self.isSending = NO;
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用发送接口
|
||||
LFFrame *frame = [self.buffer popFirstObject];
|
||||
LFFrame *frame = [_self.buffer popFirstObject];
|
||||
if ([frame isKindOfClass:[LFVideoFrame class]]) {
|
||||
if (!self.sendVideoHead) {
|
||||
self.sendVideoHead = YES;
|
||||
if (!_self.sendVideoHead) {
|
||||
_self.sendVideoHead = YES;
|
||||
if(!((LFVideoFrame*)frame).sps || !((LFVideoFrame*)frame).pps){
|
||||
self.isSending = NO;
|
||||
_self.isSending = NO;
|
||||
return;
|
||||
}
|
||||
[self sendVideoHeader:(LFVideoFrame *)frame];
|
||||
[_self sendVideoHeader:(LFVideoFrame *)frame];
|
||||
} else {
|
||||
[self sendVideo:(LFVideoFrame *)frame];
|
||||
[_self sendVideo:(LFVideoFrame *)frame];
|
||||
}
|
||||
} else {
|
||||
if (!self.sendAudioHead) {
|
||||
self.sendAudioHead = YES;
|
||||
if (!_self.sendAudioHead) {
|
||||
_self.sendAudioHead = YES;
|
||||
if(!((LFAudioFrame*)frame).audioInfo){
|
||||
self.isSending = NO;
|
||||
_self.isSending = NO;
|
||||
return;
|
||||
}
|
||||
[self sendAudioHeader:(LFAudioFrame *)frame];
|
||||
[_self sendAudioHeader:(LFAudioFrame *)frame];
|
||||
} else {
|
||||
[self sendAudio:frame];
|
||||
[_self sendAudio:frame];
|
||||
}
|
||||
}
|
||||
|
||||
//debug更新
|
||||
self.debugInfo.totalFrame++;
|
||||
self.debugInfo.dropFrame += self.buffer.lastDropFrames;
|
||||
self.buffer.lastDropFrames = 0;
|
||||
_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;
|
||||
_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++;
|
||||
_self.debugInfo.capturedAudioCount++;
|
||||
} else {
|
||||
self.debugInfo.capturedVideoCount++;
|
||||
_self.debugInfo.capturedVideoCount++;
|
||||
}
|
||||
|
||||
self.debugInfo.unSendCount = self.buffer.list.count;
|
||||
_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.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.bandwidth = 0;
|
||||
_self.debugInfo.capturedAudioCount = 0;
|
||||
_self.debugInfo.capturedVideoCount = 0;
|
||||
_self.debugInfo.timeStamp = CACurrentMediaTime() * 1000;
|
||||
}
|
||||
|
||||
//修改发送状态
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
//< 这里只为了不循环调用sendFrame方法 调用栈是保证先出栈再进栈
|
||||
self.isSending = NO;
|
||||
_self.isSending = NO;
|
||||
});
|
||||
|
||||
}
|
||||
@@ -230,18 +248,6 @@ SAVC(mp4a);
|
||||
- (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);
|
||||
|
||||
@@ -280,19 +286,13 @@ SAVC(mp4a);
|
||||
_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;
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ Failed:
|
||||
*enc++ = 0;
|
||||
*enc++ = AMF_OBJECT_END;
|
||||
|
||||
packet.m_nBodySize = enc - packet.m_body;
|
||||
packet.m_nBodySize = (uint32_t)(enc - packet.m_body);
|
||||
if (!PILI_RTMP_SendPacket(_rtmp, &packet, FALSE, &_error)) {
|
||||
return;
|
||||
}
|
||||
@@ -484,36 +484,61 @@ Failed:
|
||||
// 断线重连
|
||||
- (void)reconnect {
|
||||
dispatch_async(self.rtmpSendQueue, ^{
|
||||
_isReconnecting = NO;
|
||||
if (_isConnected) return;
|
||||
|
||||
[self _stop];
|
||||
[self _start];
|
||||
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;
|
||||
[socket performSelectorOnMainThread:@selector(reconnect) withObject:nil waitUntilDone:socket.reconnectInterval];
|
||||
} 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];
|
||||
}
|
||||
}
|
||||
[socket reconnect];
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionTimeCallback(PILI_CONNECTION_TIME *conn_time, void *userData) {
|
||||
//LFStreamRTMPSocket *socket = (__bridge LFStreamRTMPSocket*)userData;
|
||||
}
|
||||
|
||||
#pragma mark -- LFStreamingBufferDelegate
|
||||
@@ -538,7 +563,7 @@ void ConnectionTimeCallback(PILI_CONNECTION_TIME *conn_time, void *userData) {
|
||||
if (!_buffer) {
|
||||
_buffer = [[LFStreamingBuffer alloc] init];
|
||||
_buffer.delegate = self;
|
||||
_buffer.needDropFrame = self.stream.needDropFrame;
|
||||
|
||||
}
|
||||
return _buffer;
|
||||
}
|
||||
@@ -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,6 +11,8 @@
|
||||
#import "LFStreamingBuffer.h"
|
||||
#import "LFLiveDebug.h"
|
||||
|
||||
|
||||
|
||||
@protocol LFStreamSocket;
|
||||
@protocol LFStreamSocketDelegate <NSObject>
|
||||
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
// 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) {
|
||||
LFLiveBuffferUnknown = 0, //< 未知
|
||||
@@ -27,8 +28,6 @@ typedef NS_ENUM (NSUInteger, LFLiveBuffferState) {
|
||||
|
||||
@interface LFStreamingBuffer : NSObject
|
||||
|
||||
/** The needDropFrame control Dynamic frame loss ,default is YES */
|
||||
@property (nonatomic, assign) BOOL needDropFrame;
|
||||
|
||||
/** The delegate of the buffer. buffer callback */
|
||||
@property (nullable, nonatomic, weak) id <LFStreamingBufferDelegate> delegate;
|
||||
|
||||
@@ -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
|
||||
@@ -41,7 +41,6 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
|
||||
self.maxCount = defaultSendBufferMaxCount;
|
||||
self.lastDropFrames = 0;
|
||||
self.startTimer = NO;
|
||||
self.needDropFrame = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -63,9 +62,7 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
|
||||
} else {
|
||||
///< 排序
|
||||
[self.sortList addObject:frame];
|
||||
NSArray *sortedSendQuery = [self.sortList sortedArrayUsingFunction:frameDataCompare context:NULL];
|
||||
[self.sortList removeAllObjects];
|
||||
[self.sortList addObjectsFromArray:sortedSendQuery];
|
||||
[self.sortList sortUsingFunction:frameDataCompare context:nil];
|
||||
/// 丢帧
|
||||
[self removeExpireFrame];
|
||||
/// 添加至缓冲区
|
||||
@@ -92,26 +89,21 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
|
||||
- (void)removeExpireFrame {
|
||||
if (self.list.count < self.maxCount) return;
|
||||
|
||||
if(self.needDropFrame){
|
||||
NSArray *pFrames = [self expirePFrames];///< 第一个P到第一个I之间的p帧
|
||||
self.lastDropFrames += [pFrames count];
|
||||
if (pFrames && pFrames.count > 0) {
|
||||
[self.list removeObjectsInArray:pFrames];
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray *iFrames = [self expireIFrames];///< 删除一个I帧(但一个I帧可能对应多个nal)
|
||||
self.lastDropFrames += [iFrames count];
|
||||
if (iFrames) {
|
||||
[self.list removeObjectsInArray:iFrames];
|
||||
return;
|
||||
}
|
||||
|
||||
[self.list removeAllObjects];
|
||||
}else{
|
||||
[self.list lfPopFirstObject];
|
||||
NSArray *pFrames = [self expirePFrames];///< 第一个P到第一个I之间的p帧
|
||||
self.lastDropFrames += [pFrames count];
|
||||
if (pFrames && pFrames.count > 0) {
|
||||
[self.list removeObjectsInArray:pFrames];
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray *iFrames = [self expireIFrames];///< 删除一个I帧(但一个I帧可能对应多个nal)
|
||||
self.lastDropFrames += [iFrames count];
|
||||
if (iFrames && iFrames.count > 0) {
|
||||
[self.list removeObjectsInArray:iFrames];
|
||||
return;
|
||||
}
|
||||
|
||||
[self.list removeAllObjects];
|
||||
}
|
||||
|
||||
- (NSArray *)expirePFrames {
|
||||
@@ -161,9 +153,9 @@ NSInteger frameDataCompare(id obj1, id obj2, void *context){
|
||||
NSInteger decreaseCount = 0;
|
||||
|
||||
for (NSNumber *number in self.thresholdList) {
|
||||
if (number.integerValue >= currentCount) {
|
||||
if (number.integerValue > currentCount) {
|
||||
increaseCount++;
|
||||
} else {
|
||||
} else{
|
||||
decreaseCount++;
|
||||
}
|
||||
currentCount = [number integerValue];
|
||||
@@ -176,7 +168,7 @@ NSInteger frameDataCompare(id obj1, id obj2, void *context){
|
||||
if (decreaseCount >= self.callBackInterval) {
|
||||
return LFLiveBuffferDecline;
|
||||
}
|
||||
|
||||
|
||||
return LFLiveBuffferUnknown;
|
||||
}
|
||||
|
||||
@@ -210,7 +202,7 @@ NSInteger frameDataCompare(id obj1, id obj2, void *context){
|
||||
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
|
||||
[self.thresholdList addObject:@(self.list.count)];
|
||||
dispatch_semaphore_signal(_lock);
|
||||
|
||||
|
||||
if (self.currentInterval >= self.callBackInterval) {
|
||||
LFLiveBuffferState state = [self currentBufferState];
|
||||
if (state == LFLiveBuffferIncrease) {
|
||||
@@ -228,7 +220,7 @@ NSInteger frameDataCompare(id obj1, id obj2, void *context){
|
||||
}
|
||||
__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>
|
||||
|
||||
@@ -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,493 +0,0 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
81E848D8BD2C446C2DD4876A /* libPods-LFLiveKitDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FD9F92833FE7856CDDD3CED /* libPods-LFLiveKitDemo.a */; };
|
||||
84C7AFA71D52F75C00614703 /* ios-29x29.png in Resources */ = {isa = PBXBuildFile; fileRef = 84C7AFA61D52F75C00614703 /* ios-29x29.png */; };
|
||||
A9DB2F10F7A29BE365D7CA5A /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 91E73D3676F527F2A7BD7C6C /* libPods.a */; };
|
||||
B2D23E7F1D348F3D00B34CA8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D23E7E1D348F3D00B34CA8 /* main.m */; };
|
||||
B2D23E821D348F3D00B34CA8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D23E811D348F3D00B34CA8 /* AppDelegate.m */; };
|
||||
B2D23E851D348F3D00B34CA8 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D23E841D348F3D00B34CA8 /* ViewController.m */; };
|
||||
B2D23E881D348F3D00B34CA8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B2D23E861D348F3D00B34CA8 /* Main.storyboard */; };
|
||||
B2D23E8D1D348F3D00B34CA8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B2D23E8B1D348F3D00B34CA8 /* LaunchScreen.storyboard */; };
|
||||
B2D23EAA1D348F7100B34CA8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B2D23E941D348F7100B34CA8 /* Assets.xcassets */; };
|
||||
B2D23EAB1D348F7100B34CA8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B2D23E961D348F7100B34CA8 /* LaunchScreen.storyboard */; };
|
||||
B2D23EAC1D348F7100B34CA8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B2D23E981D348F7100B34CA8 /* Main.storyboard */; };
|
||||
B2D23EAD1D348F7100B34CA8 /* UIControl+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D23E9C1D348F7100B34CA8 /* UIControl+YYAdd.m */; };
|
||||
B2D23EAE1D348F7100B34CA8 /* UIView+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D23E9E1D348F7100B34CA8 /* UIView+YYAdd.m */; };
|
||||
B2D23EAF1D348F7100B34CA8 /* camra_beauty@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B2D23EA01D348F7100B34CA8 /* camra_beauty@2x.png */; };
|
||||
B2D23EB01D348F7100B34CA8 /* camra_beauty@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = B2D23EA11D348F7100B34CA8 /* camra_beauty@3x.png */; };
|
||||
B2D23EB11D348F7100B34CA8 /* camra_beauty_close@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B2D23EA21D348F7100B34CA8 /* camra_beauty_close@2x.png */; };
|
||||
B2D23EB21D348F7100B34CA8 /* camra_beauty_close@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = B2D23EA31D348F7100B34CA8 /* camra_beauty_close@3x.png */; };
|
||||
B2D23EB31D348F7100B34CA8 /* camra_preview@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B2D23EA41D348F7100B34CA8 /* camra_preview@2x.png */; };
|
||||
B2D23EB41D348F7100B34CA8 /* camra_preview@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = B2D23EA51D348F7100B34CA8 /* camra_preview@3x.png */; };
|
||||
B2D23EB51D348F7100B34CA8 /* close_preview@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B2D23EA61D348F7100B34CA8 /* close_preview@2x.png */; };
|
||||
B2D23EB61D348F7100B34CA8 /* close_preview@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = B2D23EA71D348F7100B34CA8 /* close_preview@3x.png */; };
|
||||
B2D23EB71D348F7100B34CA8 /* LFLivePreview.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D23EA91D348F7100B34CA8 /* LFLivePreview.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
6FD9F92833FE7856CDDD3CED /* libPods-LFLiveKitDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LFLiveKitDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
84C7AFA61D52F75C00614703 /* ios-29x29.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ios-29x29.png"; sourceTree = "<group>"; };
|
||||
8FAAEBE1A4F099C69588B394 /* Pods-LFLiveKitDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LFLiveKitDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo.release.xcconfig"; sourceTree = "<group>"; };
|
||||
91E73D3676F527F2A7BD7C6C /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AFD491825C5DB2AD871189B5 /* Pods-LFLiveKitDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LFLiveKitDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B2D23E7A1D348F3D00B34CA8 /* LFLiveKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LFLiveKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B2D23E7E1D348F3D00B34CA8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
B2D23E801D348F3D00B34CA8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
B2D23E811D348F3D00B34CA8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
B2D23E831D348F3D00B34CA8 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
|
||||
B2D23E841D348F3D00B34CA8 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
|
||||
B2D23E871D348F3D00B34CA8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
B2D23E8C1D348F3D00B34CA8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
B2D23E8E1D348F3D00B34CA8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
B2D23E941D348F7100B34CA8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
B2D23E971D348F7100B34CA8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
B2D23E991D348F7100B34CA8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Main.storyboard; sourceTree = "<group>"; };
|
||||
B2D23E9B1D348F7100B34CA8 /* UIControl+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIControl+YYAdd.h"; sourceTree = "<group>"; };
|
||||
B2D23E9C1D348F7100B34CA8 /* UIControl+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIControl+YYAdd.m"; sourceTree = "<group>"; };
|
||||
B2D23E9D1D348F7100B34CA8 /* UIView+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+YYAdd.h"; sourceTree = "<group>"; };
|
||||
B2D23E9E1D348F7100B34CA8 /* UIView+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+YYAdd.m"; sourceTree = "<group>"; };
|
||||
B2D23EA01D348F7100B34CA8 /* camra_beauty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty@2x.png"; sourceTree = "<group>"; };
|
||||
B2D23EA11D348F7100B34CA8 /* camra_beauty@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty@3x.png"; sourceTree = "<group>"; };
|
||||
B2D23EA21D348F7100B34CA8 /* camra_beauty_close@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty_close@2x.png"; sourceTree = "<group>"; };
|
||||
B2D23EA31D348F7100B34CA8 /* camra_beauty_close@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty_close@3x.png"; sourceTree = "<group>"; };
|
||||
B2D23EA41D348F7100B34CA8 /* camra_preview@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_preview@2x.png"; sourceTree = "<group>"; };
|
||||
B2D23EA51D348F7100B34CA8 /* camra_preview@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_preview@3x.png"; sourceTree = "<group>"; };
|
||||
B2D23EA61D348F7100B34CA8 /* close_preview@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "close_preview@2x.png"; sourceTree = "<group>"; };
|
||||
B2D23EA71D348F7100B34CA8 /* close_preview@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "close_preview@3x.png"; sourceTree = "<group>"; };
|
||||
B2D23EA81D348F7100B34CA8 /* LFLivePreview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLivePreview.h; sourceTree = "<group>"; };
|
||||
B2D23EA91D348F7100B34CA8 /* LFLivePreview.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLivePreview.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
B2D23E771D348F3D00B34CA8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
81E848D8BD2C446C2DD4876A /* libPods-LFLiveKitDemo.a in Frameworks */,
|
||||
A9DB2F10F7A29BE365D7CA5A /* libPods.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
2A74A5AD65CD9450ED23C3E0 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AFD491825C5DB2AD871189B5 /* Pods-LFLiveKitDemo.debug.xcconfig */,
|
||||
8FAAEBE1A4F099C69588B394 /* Pods-LFLiveKitDemo.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2D23E711D348F3D00B34CA8 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B2D23E7C1D348F3D00B34CA8 /* LFLiveKitDemo */,
|
||||
B2D23E7B1D348F3D00B34CA8 /* Products */,
|
||||
2A74A5AD65CD9450ED23C3E0 /* Pods */,
|
||||
E6AF2D0BFA2946745BB5F365 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2D23E7B1D348F3D00B34CA8 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B2D23E7A1D348F3D00B34CA8 /* LFLiveKitDemo.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2D23E7C1D348F3D00B34CA8 /* LFLiveKitDemo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B2D23E941D348F7100B34CA8 /* Assets.xcassets */,
|
||||
B2D23E951D348F7100B34CA8 /* Base.lproj */,
|
||||
B2D23E9A1D348F7100B34CA8 /* category */,
|
||||
B2D23E9F1D348F7100B34CA8 /* images */,
|
||||
B2D23EA81D348F7100B34CA8 /* LFLivePreview.h */,
|
||||
B2D23EA91D348F7100B34CA8 /* LFLivePreview.m */,
|
||||
B2D23E801D348F3D00B34CA8 /* AppDelegate.h */,
|
||||
B2D23E811D348F3D00B34CA8 /* AppDelegate.m */,
|
||||
B2D23E831D348F3D00B34CA8 /* ViewController.h */,
|
||||
B2D23E841D348F3D00B34CA8 /* ViewController.m */,
|
||||
B2D23E861D348F3D00B34CA8 /* Main.storyboard */,
|
||||
B2D23E8B1D348F3D00B34CA8 /* LaunchScreen.storyboard */,
|
||||
B2D23E8E1D348F3D00B34CA8 /* Info.plist */,
|
||||
B2D23E7D1D348F3D00B34CA8 /* Supporting Files */,
|
||||
);
|
||||
path = LFLiveKitDemo;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2D23E7D1D348F3D00B34CA8 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B2D23E7E1D348F3D00B34CA8 /* main.m */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2D23E951D348F7100B34CA8 /* Base.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B2D23E961D348F7100B34CA8 /* LaunchScreen.storyboard */,
|
||||
B2D23E981D348F7100B34CA8 /* Main.storyboard */,
|
||||
);
|
||||
path = Base.lproj;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2D23E9A1D348F7100B34CA8 /* category */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B2D23E9B1D348F7100B34CA8 /* UIControl+YYAdd.h */,
|
||||
B2D23E9C1D348F7100B34CA8 /* UIControl+YYAdd.m */,
|
||||
B2D23E9D1D348F7100B34CA8 /* UIView+YYAdd.h */,
|
||||
B2D23E9E1D348F7100B34CA8 /* UIView+YYAdd.m */,
|
||||
);
|
||||
path = category;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2D23E9F1D348F7100B34CA8 /* images */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B2D23EA01D348F7100B34CA8 /* camra_beauty@2x.png */,
|
||||
B2D23EA11D348F7100B34CA8 /* camra_beauty@3x.png */,
|
||||
B2D23EA21D348F7100B34CA8 /* camra_beauty_close@2x.png */,
|
||||
B2D23EA31D348F7100B34CA8 /* camra_beauty_close@3x.png */,
|
||||
B2D23EA41D348F7100B34CA8 /* camra_preview@2x.png */,
|
||||
B2D23EA51D348F7100B34CA8 /* camra_preview@3x.png */,
|
||||
B2D23EA61D348F7100B34CA8 /* close_preview@2x.png */,
|
||||
B2D23EA71D348F7100B34CA8 /* close_preview@3x.png */,
|
||||
84C7AFA61D52F75C00614703 /* ios-29x29.png */,
|
||||
);
|
||||
path = images;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E6AF2D0BFA2946745BB5F365 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6FD9F92833FE7856CDDD3CED /* libPods-LFLiveKitDemo.a */,
|
||||
91E73D3676F527F2A7BD7C6C /* libPods.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
B2D23E791D348F3D00B34CA8 /* LFLiveKitDemo */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = B2D23E911D348F3D00B34CA8 /* Build configuration list for PBXNativeTarget "LFLiveKitDemo" */;
|
||||
buildPhases = (
|
||||
D4A28B8E7B3F14FE7B5CE784 /* Check Pods Manifest.lock */,
|
||||
B2D23E761D348F3D00B34CA8 /* Sources */,
|
||||
B2D23E771D348F3D00B34CA8 /* Frameworks */,
|
||||
B2D23E781D348F3D00B34CA8 /* Resources */,
|
||||
3E1A58B9B801624E131D1416 /* Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = LFLiveKitDemo;
|
||||
productName = LFLiveKitDemo;
|
||||
productReference = B2D23E7A1D348F3D00B34CA8 /* LFLiveKitDemo.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
B2D23E721D348F3D00B34CA8 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0730;
|
||||
ORGANIZATIONNAME = zhanqi.tv;
|
||||
TargetAttributes = {
|
||||
B2D23E791D348F3D00B34CA8 = {
|
||||
CreatedOnToolsVersion = 7.3;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = B2D23E751D348F3D00B34CA8 /* Build configuration list for PBXProject "LFLiveKitDemo" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = B2D23E711D348F3D00B34CA8;
|
||||
productRefGroup = B2D23E7B1D348F3D00B34CA8 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
B2D23E791D348F3D00B34CA8 /* LFLiveKitDemo */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
B2D23E781D348F3D00B34CA8 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B2D23E8D1D348F3D00B34CA8 /* LaunchScreen.storyboard in Resources */,
|
||||
B2D23EAA1D348F7100B34CA8 /* Assets.xcassets in Resources */,
|
||||
84C7AFA71D52F75C00614703 /* ios-29x29.png in Resources */,
|
||||
B2D23EAC1D348F7100B34CA8 /* Main.storyboard in Resources */,
|
||||
B2D23EAB1D348F7100B34CA8 /* LaunchScreen.storyboard in Resources */,
|
||||
B2D23EB21D348F7100B34CA8 /* camra_beauty_close@3x.png in Resources */,
|
||||
B2D23EAF1D348F7100B34CA8 /* camra_beauty@2x.png in Resources */,
|
||||
B2D23EB61D348F7100B34CA8 /* close_preview@3x.png in Resources */,
|
||||
B2D23EB41D348F7100B34CA8 /* camra_preview@3x.png in Resources */,
|
||||
B2D23EB51D348F7100B34CA8 /* close_preview@2x.png in Resources */,
|
||||
B2D23EB11D348F7100B34CA8 /* camra_beauty_close@2x.png in Resources */,
|
||||
B2D23EB01D348F7100B34CA8 /* camra_beauty@3x.png in Resources */,
|
||||
B2D23EB31D348F7100B34CA8 /* camra_preview@2x.png in Resources */,
|
||||
B2D23E881D348F3D00B34CA8 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3E1A58B9B801624E131D1416 /* 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/Pods-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
D4A28B8E7B3F14FE7B5CE784 /* 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 */
|
||||
B2D23E761D348F3D00B34CA8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B2D23EB71D348F7100B34CA8 /* LFLivePreview.m in Sources */,
|
||||
B2D23E851D348F3D00B34CA8 /* ViewController.m in Sources */,
|
||||
B2D23EAD1D348F7100B34CA8 /* UIControl+YYAdd.m in Sources */,
|
||||
B2D23E821D348F3D00B34CA8 /* AppDelegate.m in Sources */,
|
||||
B2D23EAE1D348F7100B34CA8 /* UIView+YYAdd.m in Sources */,
|
||||
B2D23E7F1D348F3D00B34CA8 /* main.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
B2D23E861D348F3D00B34CA8 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
B2D23E871D348F3D00B34CA8 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2D23E8B1D348F3D00B34CA8 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
B2D23E8C1D348F3D00B34CA8 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2D23E961D348F7100B34CA8 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
B2D23E971D348F7100B34CA8 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2D23E981D348F7100B34CA8 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
B2D23E991D348F7100B34CA8 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
B2D23E8F1D348F3D00B34CA8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
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;
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B2D23E901D348F3D00B34CA8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
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;
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
B2D23E921D348F3D00B34CA8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = AFD491825C5DB2AD871189B5 /* Pods-LFLiveKitDemo.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = LFLiveKitDemo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.gameabc.LFLiveKitDemo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B2D23E931D348F3D00B34CA8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8FAAEBE1A4F099C69588B394 /* Pods-LFLiveKitDemo.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = LFLiveKitDemo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.gameabc.LFLiveKitDemo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
B2D23E751D348F3D00B34CA8 /* Build configuration list for PBXProject "LFLiveKitDemo" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B2D23E8F1D348F3D00B34CA8 /* Debug */,
|
||||
B2D23E901D348F3D00B34CA8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
B2D23E911D348F3D00B34CA8 /* Build configuration list for PBXNativeTarget "LFLiveKitDemo" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B2D23E921D348F3D00B34CA8 /* Debug */,
|
||||
B2D23E931D348F3D00B34CA8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = B2D23E721D348F3D00B34CA8 /* Project object */;
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:LFLiveKitDemo.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
BIN
Binary file not shown.
-111
@@ -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>
|
||||
-37
@@ -1,37 +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>
|
||||
<key>B2D23E791D348F3D00B34CA8</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
-22
@@ -1,22 +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>5</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>B2D23E791D348F3D00B34CA8</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>
|
||||
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
@@ -1,4 +0,0 @@
|
||||
|
||||
#CocoaPods
|
||||
Pods/
|
||||
Podfile.lock
|
||||
Generated
-7
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:LFLiveKitSwiftDemo.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
BIN
Binary file not shown.
-22
@@ -1,22 +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>LFLiveKitSwiftDemo.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>B2C8FAC01D3DB8B3008D44B5</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:LFLiveKitSwiftDemo.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
BIN
Binary file not shown.
-5
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Bucket
|
||||
type = "0"
|
||||
version = "2.0">
|
||||
</Bucket>
|
||||
@@ -1,10 +0,0 @@
|
||||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
#ifndef LFLiveKitSwiftDemo_Bridging_H
|
||||
#define LFLiveKitSwiftDemo_Bridging_H
|
||||
|
||||
#import <LFLiveKit.h>
|
||||
|
||||
#endif
|
||||
@@ -1,222 +0,0 @@
|
||||
//
|
||||
// ViewController.swift
|
||||
// LFLiveKitSwiftDemo
|
||||
//
|
||||
// Created by feng on 16/7/19.
|
||||
// Copyright © 2016年 zhanqi.tv. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class ViewController: UIViewController, LFLiveSessionDelegate {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
self.requestAccessForVideo()
|
||||
self.requestAccessForAudio()
|
||||
self.view.backgroundColor = UIColor.clearColor()
|
||||
self.view.addSubview(containerView)
|
||||
containerView.addSubview(stateLabel)
|
||||
containerView.addSubview(closeButton)
|
||||
containerView.addSubview(beautyButton)
|
||||
containerView.addSubview(cameraButton)
|
||||
containerView.addSubview(startLiveButton)
|
||||
}
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
super.didReceiveMemoryWarning()
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
//MARK: AccessAuth
|
||||
|
||||
func requestAccessForVideo() -> Void {
|
||||
let status = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)
|
||||
switch status {
|
||||
// 许可对话没有出现,发起授权许可
|
||||
case AVAuthorizationStatus.NotDetermined:
|
||||
AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (granted) in
|
||||
if (granted) {
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
self.session.running = true;
|
||||
});
|
||||
}
|
||||
})
|
||||
break;
|
||||
// 已经开启授权,可继续
|
||||
case AVAuthorizationStatus.Authorized:
|
||||
session.running = true;
|
||||
break;
|
||||
// 用户明确地拒绝授权,或者相机设备无法访问
|
||||
case AVAuthorizationStatus.Denied: break
|
||||
case AVAuthorizationStatus.Restricted:break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
func requestAccessForAudio() -> Void {
|
||||
let status = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeAudio)
|
||||
switch status {
|
||||
// 许可对话没有出现,发起授权许可
|
||||
case AVAuthorizationStatus.NotDetermined:
|
||||
AVCaptureDevice.requestAccessForMediaType(AVMediaTypeAudio, completionHandler: { (granted) in
|
||||
})
|
||||
break;
|
||||
// 已经开启授权,可继续
|
||||
case AVAuthorizationStatus.Authorized:
|
||||
break;
|
||||
// 用户明确地拒绝授权,或者相机设备无法访问
|
||||
case AVAuthorizationStatus.Denied: break
|
||||
case AVAuthorizationStatus.Restricted:break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - Callbacks
|
||||
|
||||
// 回调
|
||||
func liveSession(session: LFLiveSession?, debugInfo: LFLiveDebug?) {
|
||||
print("debugInfo: \(debugInfo?.currentBandwidth)")
|
||||
}
|
||||
|
||||
func liveSession(session: LFLiveSession?, errorCode: LFLiveSocketErrorCode) {
|
||||
print("errorCode: \(errorCode.rawValue)")
|
||||
}
|
||||
|
||||
func liveSession(session: LFLiveSession?, liveStateDidChange state: LFLiveState) {
|
||||
print("liveStateDidChange: \(state.rawValue)")
|
||||
switch state {
|
||||
case LFLiveState.Ready:
|
||||
stateLabel.text = "未连接"
|
||||
break;
|
||||
case LFLiveState.Pending:
|
||||
stateLabel.text = "连接中"
|
||||
break;
|
||||
case LFLiveState.Start:
|
||||
stateLabel.text = "已连接"
|
||||
break;
|
||||
case LFLiveState.Error:
|
||||
stateLabel.text = "连接错误"
|
||||
break;
|
||||
case LFLiveState.Stop:
|
||||
stateLabel.text = "未连接"
|
||||
break;
|
||||
default:
|
||||
stateLabel.text = "未知"
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - Events
|
||||
|
||||
// 开始直播
|
||||
func didTappedStartLiveButton(button: UIButton) -> Void {
|
||||
startLiveButton.selected = !startLiveButton.selected;
|
||||
if (startLiveButton.selected) {
|
||||
startLiveButton.setTitle("结束直播", forState: UIControlState.Normal)
|
||||
let stream = LFLiveStreamInfo()
|
||||
stream.url = "rtmp://30.96.179.95:1935/live/1234"
|
||||
session.startLive(stream)
|
||||
} else {
|
||||
startLiveButton.setTitle("开始直播", forState: UIControlState.Normal)
|
||||
session.stopLive()
|
||||
}
|
||||
}
|
||||
|
||||
// 美颜
|
||||
func didTappedBeautyButton(button: UIButton) -> Void {
|
||||
session.beautyFace = !session.beautyFace;
|
||||
beautyButton.selected = !session.beautyFace;
|
||||
}
|
||||
|
||||
// 摄像头
|
||||
func didTappedCameraButton(button: UIButton) -> Void {
|
||||
let devicePositon = session.captureDevicePosition;
|
||||
session.captureDevicePosition = (devicePositon == AVCaptureDevicePosition.Back) ? AVCaptureDevicePosition.Front : AVCaptureDevicePosition.Back;
|
||||
}
|
||||
|
||||
// 关闭
|
||||
func didTappedCloseButton(button: UIButton) -> Void {
|
||||
|
||||
}
|
||||
|
||||
//MARK: - Getters and Setters
|
||||
|
||||
// 默认分辨率368 * 640 音频:44.1 iphone6以上48 双声道 方向竖屏
|
||||
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!
|
||||
}()
|
||||
|
||||
// 视图
|
||||
lazy var containerView: UIView = {
|
||||
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height))
|
||||
containerView.backgroundColor = UIColor.clearColor()
|
||||
containerView.autoresizingMask = [UIViewAutoresizing.FlexibleHeight, UIViewAutoresizing.FlexibleHeight]
|
||||
return containerView
|
||||
}()
|
||||
|
||||
// 状态Label
|
||||
lazy var stateLabel: UILabel = {
|
||||
let stateLabel = UILabel(frame: CGRect(x: 20, y: 20, width: 80, height: 40))
|
||||
stateLabel.text = "未连接"
|
||||
stateLabel.textColor = UIColor.whiteColor()
|
||||
stateLabel.font = UIFont.systemFontOfSize(14)
|
||||
return stateLabel
|
||||
}()
|
||||
|
||||
// 关闭按钮
|
||||
lazy var closeButton: UIButton = {
|
||||
let closeButton = UIButton(frame: CGRect(x: self.view.frame.width - 10 - 44, y: 20, width: 44, height: 44))
|
||||
closeButton.setImage(UIImage(named: "close_preview"), forState: UIControlState.Normal)
|
||||
closeButton.addTarget(self, action: #selector(didTappedCloseButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)
|
||||
return closeButton
|
||||
}()
|
||||
|
||||
// 摄像头
|
||||
lazy var cameraButton: UIButton = {
|
||||
let cameraButton = UIButton(frame: CGRect(x: self.view.frame.width - 54 * 2, y: 20, width: 44, height: 44))
|
||||
cameraButton.setImage(UIImage(named: "camra_preview"), forState: UIControlState.Normal)
|
||||
cameraButton.addTarget(self, action: #selector(didTappedCameraButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)
|
||||
return cameraButton
|
||||
}()
|
||||
|
||||
// 摄像头
|
||||
lazy var beautyButton: UIButton = {
|
||||
let beautyButton = UIButton(frame: CGRect(x: self.view.frame.width - 54 * 3, y: 20, width: 44, height: 44))
|
||||
beautyButton.setImage(UIImage(named: "camra_preview"), forState: UIControlState.Selected)
|
||||
beautyButton.setImage(UIImage(named: "camra_beauty_close"), forState: UIControlState.Normal)
|
||||
beautyButton.addTarget(self, action: #selector(didTappedBeautyButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)
|
||||
return beautyButton
|
||||
}()
|
||||
|
||||
// 开始直播按钮
|
||||
lazy var startLiveButton: UIButton = {
|
||||
let startLiveButton = UIButton(frame: CGRect(x: 30, y: self.view.frame.height - 50, width: self.view.frame.width - 10 - 44, height: 44))
|
||||
startLiveButton.layer.cornerRadius = 22
|
||||
startLiveButton.setTitleColor(UIColor.blackColor(), forState:UIControlState.Normal)
|
||||
startLiveButton.setTitle("开始直播", forState: UIControlState.Normal)
|
||||
startLiveButton.titleLabel!.font = UIFont.systemFontOfSize(14)
|
||||
startLiveButton.backgroundColor = UIColor(colorLiteralRed: 50, green: 32, blue: 245, alpha: 1)
|
||||
startLiveButton.addTarget(self, action: #selector(didTappedStartLiveButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)
|
||||
return startLiveButton
|
||||
}()
|
||||
|
||||
// 转屏
|
||||
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
|
||||
return UIInterfaceOrientationMask.Portrait
|
||||
}
|
||||
|
||||
override func shouldAutorotate() -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios,'7.0'
|
||||
|
||||
target 'LFLiveKitSwiftDemo' do
|
||||
pod 'LFLiveKit', path: '../'
|
||||
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,6 +1,6 @@
|
||||
LFLiveKit
|
||||
==============
|
||||

|
||||

|
||||
|
||||
|
||||
[](https://travis-ci.org/LaiFengiOS/LFLiveKit)
|
||||
@@ -66,71 +66,76 @@ LFLiveKit
|
||||
* VideoToolbox
|
||||
* AudioToolbox
|
||||
* libz
|
||||
* libstdc++
|
||||
|
||||
## Usage example
|
||||
|
||||
#### Objective-C
|
||||
```objc
|
||||
- (LFLiveSession*)session {
|
||||
if (!_session) {
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration]];
|
||||
_session.preView = self;
|
||||
_session.delegate = self;
|
||||
}
|
||||
return _session;
|
||||
}
|
||||
|
||||
- (LFLiveSession*)session {
|
||||
if (!_session) {
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration]];
|
||||
_session.preView = self;
|
||||
_session.delegate = self;
|
||||
}
|
||||
return _session;
|
||||
}
|
||||
|
||||
- (void)startLive {
|
||||
LFLiveStreamInfo *streamInfo = [LFLiveStreamInfo new];
|
||||
streamInfo.url = @"your server rtmp url";
|
||||
[self.session startLive:streamInfo];
|
||||
}
|
||||
- (void)startLive {
|
||||
LFLiveStreamInfo *streamInfo = [LFLiveStreamInfo new];
|
||||
streamInfo.url = @"your server rtmp url";
|
||||
[self.session startLive:streamInfo];
|
||||
}
|
||||
|
||||
- (void)stopLive {
|
||||
[self.session stopLive];
|
||||
}
|
||||
|
||||
//MARK: - CallBack:
|
||||
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange: (LFLiveState)state;
|
||||
- (void)liveSession:(nullable LFLiveSession *)session debugInfo:(nullable LFLiveDebug*)debugInfo;
|
||||
- (void)liveSession:(nullable LFLiveSession*)session errorCode:(LFLiveSocketErrorCode)errorCode;
|
||||
- (void)stopLive {
|
||||
[self.session stopLive];
|
||||
}
|
||||
|
||||
//MARK: - CallBack:
|
||||
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange: (LFLiveState)state;
|
||||
- (void)liveSession:(nullable LFLiveSession *)session debugInfo:(nullable LFLiveDebug*)debugInfo;
|
||||
- (void)liveSession:(nullable LFLiveSession*)session errorCode:(LFLiveSocketErrorCode)errorCode;
|
||||
```
|
||||
#### Swift
|
||||
```swift
|
||||
// import LFLiveKit in [ProjectName]-Bridging-Header.h
|
||||
#import <LFLiveKit.h>
|
||||
|
||||
// import LFLiveKit in [ProjectName]-Bridging-Header.h
|
||||
import <LFLiveKit.h>
|
||||
//MARK: - Getters and Setters
|
||||
lazy var session: LFLiveSession = {
|
||||
let audioConfiguration = LFLiveAudioConfiguration.defaultConfiguration()
|
||||
let videoConfiguration = LFLiveVideoConfiguration.defaultConfigurationForQuality(LFLiveVideoQuality.Low3, landscape: false)
|
||||
let session = LFLiveSession(audioConfiguration: audioConfiguration, videoConfiguration: videoConfiguration)
|
||||
|
||||
session?.delegate = self
|
||||
session?.preView = self.view
|
||||
return session!
|
||||
}()
|
||||
|
||||
//MARK: - Getters and Setters
|
||||
lazy var session: LFLiveSession = {
|
||||
let audioConfiguration = LFLiveAudioConfiguration.defaultConfiguration()
|
||||
let videoConfiguration = LFLiveVideoConfiguration.defaultConfigurationForQuality(LFLiveVideoQuality.Low3, landscape: false)
|
||||
let session = LFLiveSession(audioConfiguration: audioConfiguration, videoConfiguration: videoConfiguration)
|
||||
|
||||
session?.delegate = self
|
||||
session?.preView = self.view
|
||||
return session!
|
||||
}()
|
||||
//MARK: - Event
|
||||
func startLive() -> Void {
|
||||
let stream = LFLiveStreamInfo()
|
||||
stream.url = "your server rtmp url";
|
||||
session.startLive(stream)
|
||||
}
|
||||
|
||||
//MARK: - Event
|
||||
func startLive() -> Void {
|
||||
let stream = LFLiveStreamInfo()
|
||||
stream.url = "your server rtmp url";
|
||||
session.startLive(stream)
|
||||
}
|
||||
|
||||
func stopLive() -> Void {
|
||||
session.stopLive()
|
||||
}
|
||||
|
||||
//MARK: - Callback
|
||||
func liveSession(session: LFLiveSession?, debugInfo: LFLiveDebug?)
|
||||
func liveSession(session: LFLiveSession?, errorCode: LFLiveSocketErrorCode)
|
||||
func liveSession(session: LFLiveSession?, liveStateDidChange state: LFLiveState)
|
||||
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.
|
||||
* 2.5
|
||||
* CHANGE: modify bugs,support bitcode.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,472 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
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 */
|
||||
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 */
|
||||
84D8B4231D75778B00752B56 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84D8B4CF1D757F0700752B56 /* libstdc++.tbd in Frameworks */,
|
||||
BC8B37EEE1CEEF9B5614DC91 /* libPods-LFLiveKitDemo.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
65E0CF98FF954863E543A0E1 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B1CCEEE06FCFAF75D105A51 /* libPods-LFLiveKitDemo.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B41D1D75778B00752B56 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B4CE1D757F0700752B56 /* libstdc++.tbd */,
|
||||
84D8B4281D75778B00752B56 /* LFLiveKitDemo */,
|
||||
84D8B4271D75778B00752B56 /* Products */,
|
||||
F3E359B8A7561F963C47A62F /* Pods */,
|
||||
65E0CF98FF954863E543A0E1 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B4271D75778B00752B56 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B4261D75778B00752B56 /* LFLiveKitDemo.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B4281D75778B00752B56 /* LFLiveKitDemo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
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>";
|
||||
};
|
||||
84D8B4291D75778B00752B56 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B42A1D75778B00752B56 /* main.m */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B44C1D75782700752B56 /* category */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B44D1D75782700752B56 /* UIControl+YYAdd.h */,
|
||||
84D8B44E1D75782700752B56 /* UIControl+YYAdd.m */,
|
||||
84D8B44F1D75782700752B56 /* UIView+YYAdd.h */,
|
||||
84D8B4501D75782700752B56 /* UIView+YYAdd.m */,
|
||||
);
|
||||
path = category;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B4511D75782700752B56 /* images */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
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>";
|
||||
};
|
||||
F3E359B8A7561F963C47A62F /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
289A9C4510CD7EA6F4CE9897 /* Pods-LFLiveKitDemo.debug.xcconfig */,
|
||||
96E1231310083A3881AD2AB6 /* Pods-LFLiveKitDemo.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
84D8B4251D75778B00752B56 /* LFLiveKitDemo */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 84D8B43D1D75778B00752B56 /* Build configuration list for PBXNativeTarget "LFLiveKitDemo" */;
|
||||
buildPhases = (
|
||||
A819C09CC049A57DC5C97E12 /* 📦 Check Pods Manifest.lock */,
|
||||
84D8B4221D75778B00752B56 /* Sources */,
|
||||
84D8B4231D75778B00752B56 /* Frameworks */,
|
||||
84D8B4241D75778B00752B56 /* Resources */,
|
||||
883533331BE4DCC0DB5075CF /* 📦 Embed Pods Frameworks */,
|
||||
4CC4C37B93D109913E475307 /* 📦 Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = LFLiveKitDemo;
|
||||
productName = LFLiveKitDemo;
|
||||
productReference = 84D8B4261D75778B00752B56 /* LFLiveKitDemo.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
84D8B41E1D75778B00752B56 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0730;
|
||||
ORGANIZATIONNAME = admin;
|
||||
TargetAttributes = {
|
||||
84D8B4251D75778B00752B56 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
DevelopmentTeam = G497YX6CBT;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 84D8B4211D75778B00752B56 /* Build configuration list for PBXProject "LFLiveKitDemo" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 84D8B41D1D75778B00752B56;
|
||||
productRefGroup = 84D8B4271D75778B00752B56 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
84D8B4251D75778B00752B56 /* LFLiveKitDemo */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
84D8B4241D75778B00752B56 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
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 */
|
||||
4CC4C37B93D109913E475307 /* 📦 Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
883533331BE4DCC0DB5075CF /* 📦 Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
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 */
|
||||
84D8B4221D75778B00752B56 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
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 */
|
||||
84D8B4321D75778B00752B56 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
84D8B4331D75778B00752B56 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B4371D75778B00752B56 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
84D8B4381D75778B00752B56 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
84D8B43B1D75778B00752B56 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
84D8B43C1D75778B00752B56 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
84D8B43E1D75778B00752B56 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 289A9C4510CD7EA6F4CE9897 /* Pods-LFLiveKitDemo.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
DEVELOPMENT_TEAM = G497YX6CBT;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = LFLiveKitDemo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LaiFeng;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
84D8B43F1D75778B00752B56 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 96E1231310083A3881AD2AB6 /* Pods-LFLiveKitDemo.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
DEVELOPMENT_TEAM = G497YX6CBT;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = LFLiveKitDemo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LaiFeng;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
84D8B4211D75778B00752B56 /* Build configuration list for PBXProject "LFLiveKitDemo" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
84D8B43B1D75778B00752B56 /* Debug */,
|
||||
84D8B43C1D75778B00752B56 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
84D8B43D1D75778B00752B56 /* Build configuration list for PBXNativeTarget "LFLiveKitDemo" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
84D8B43E1D75778B00752B56 /* Debug */,
|
||||
84D8B43F1D75778B00752B56 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 84D8B41E1D75778B00752B56 /* Project object */;
|
||||
}
|
||||
+1
-1
@@ -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.
|
||||
//
|
||||
|
||||
+1
-10
@@ -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.
|
||||
+6
-12
@@ -22,26 +22,20 @@
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>audio</string>
|
||||
</array>
|
||||
<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>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
+374
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
+10
-10
@@ -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 |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user