initial commit
This commit is contained in:
31
Example/SellyCloudSDK/Base.lproj/LaunchScreen.storyboard
Normal file
31
Example/SellyCloudSDK/Base.lproj/LaunchScreen.storyboard
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
426
Example/SellyCloudSDK/Base.lproj/Main.storyboard
Normal file
426
Example/SellyCloudSDK/Base.lproj/Main.storyboard
Normal file
@@ -0,0 +1,426 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24127" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="i6i-Nx-5iC">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24063"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="rhE-U3-mJu">
|
||||
<objects>
|
||||
<navigationController id="i6i-Nx-5iC" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="fGc-zP-tbz">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="whP-gf-Uak" kind="relationship" relationship="rootViewController" id="QzP-v9-gmc"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dTW-jJ-oKH" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-1719" y="-84"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="wQg-tq-qST">
|
||||
<objects>
|
||||
<viewController id="whP-gf-Uak" customClass="SCViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="uEw-UM-LJ8"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="Mvr-aV-6Um"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="TpU-gO-2f1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="纯语音模式" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="I8T-3g-j1c">
|
||||
<rect key="frame" x="26" y="74" width="85" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="eNE-Sg-1oo">
|
||||
<rect key="frame" x="294" y="70.5" width="63" height="28"/>
|
||||
</switch>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="PIl-y0-S6k">
|
||||
<rect key="frame" x="12" y="330" width="351" height="50"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="IlC-J7-Yz0">
|
||||
<rect key="frame" x="10" y="8" width="226" height="34"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="34" id="Lnn-BZ-Vi1"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tYm-wx-XZJ" customClass="SCButton">
|
||||
<rect key="frame" x="251" y="7.5" width="90" height="35"/>
|
||||
<color key="backgroundColor" red="0.47450980392156861" green="0.40000000000000002" blue="0.98039215686274506" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="35" id="gmh-c0-xcx"/>
|
||||
<constraint firstAttribute="width" constant="90" id="urY-nx-INP"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="推流">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="startLive:" destination="whP-gf-Uak" eventType="touchUpInside" id="KfT-mh-lkK"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="tYm-wx-XZJ" firstAttribute="leading" secondItem="IlC-J7-Yz0" secondAttribute="trailing" constant="15" id="8G0-fF-4VO"/>
|
||||
<constraint firstAttribute="height" constant="50" id="aCU-WA-RBp"/>
|
||||
<constraint firstAttribute="trailing" secondItem="tYm-wx-XZJ" secondAttribute="trailing" constant="10" id="b5S-fE-aWZ"/>
|
||||
<constraint firstItem="tYm-wx-XZJ" firstAttribute="centerY" secondItem="PIl-y0-S6k" secondAttribute="centerY" id="hjh-Bh-Mwk"/>
|
||||
<constraint firstItem="IlC-J7-Yz0" firstAttribute="centerY" secondItem="PIl-y0-S6k" secondAttribute="centerY" id="jNK-tp-T6A"/>
|
||||
<constraint firstItem="IlC-J7-Yz0" firstAttribute="leading" secondItem="PIl-y0-S6k" secondAttribute="leading" constant="10" id="ucd-zN-LuQ"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="PrS-3B-i8N">
|
||||
<rect key="frame" x="12" y="380" width="351" height="50"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="oHO-o9-X3f">
|
||||
<rect key="frame" x="10" y="8" width="226" height="34"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="34" id="4mL-ef-Htx"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="TJH-fG-u8J" customClass="SCButton">
|
||||
<rect key="frame" x="251" y="7.5" width="90" height="35"/>
|
||||
<color key="backgroundColor" red="0.47450980390000003" green="0.40000000000000002" blue="0.98039215690000003" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="35" id="7FR-G3-vyk"/>
|
||||
<constraint firstAttribute="width" constant="90" id="MZk-Ca-bM8"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="拉流">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="startPlay:" destination="whP-gf-Uak" eventType="touchUpInside" id="es2-2E-7MO"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="oHO-o9-X3f" firstAttribute="centerY" secondItem="PrS-3B-i8N" secondAttribute="centerY" id="D1e-0q-Qr5"/>
|
||||
<constraint firstAttribute="height" constant="50" id="FfI-Ij-hQv"/>
|
||||
<constraint firstItem="TJH-fG-u8J" firstAttribute="leading" secondItem="oHO-o9-X3f" secondAttribute="trailing" constant="15" id="U3m-Xg-mRv"/>
|
||||
<constraint firstItem="oHO-o9-X3f" firstAttribute="leading" secondItem="PrS-3B-i8N" secondAttribute="leading" constant="10" id="Y3I-Eh-W0g"/>
|
||||
<constraint firstItem="TJH-fG-u8J" firstAttribute="centerY" secondItem="PrS-3B-i8N" secondAttribute="centerY" id="Y4P-hJ-7Xz"/>
|
||||
<constraint firstAttribute="trailing" secondItem="TJH-fG-u8J" secondAttribute="trailing" constant="10" id="wCW-pA-UvO"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lk5-Bh-v0N">
|
||||
<rect key="frame" x="12" y="150" width="351" height="40"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="wV9-qB-JGb">
|
||||
<rect key="frame" x="123" y="3" width="208" height="34"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="34" id="Eyi-Ca-1mG"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="码率max:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vDv-xW-x2P">
|
||||
<rect key="frame" x="8" y="9.5" width="100" height="21"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="100" id="2Qo-IT-d1H"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="kbps" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TdU-CL-C9i">
|
||||
<rect key="frame" x="289" y="11.5" width="32" height="17"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="wV9-qB-JGb" firstAttribute="centerY" secondItem="lk5-Bh-v0N" secondAttribute="centerY" id="1hT-0e-U4n"/>
|
||||
<constraint firstItem="TdU-CL-C9i" firstAttribute="centerY" secondItem="wV9-qB-JGb" secondAttribute="centerY" id="3BW-IQ-N0s"/>
|
||||
<constraint firstItem="vDv-xW-x2P" firstAttribute="centerY" secondItem="lk5-Bh-v0N" secondAttribute="centerY" id="3Es-RX-pWn"/>
|
||||
<constraint firstAttribute="height" constant="40" id="AAy-6z-2EF"/>
|
||||
<constraint firstItem="TdU-CL-C9i" firstAttribute="trailing" secondItem="wV9-qB-JGb" secondAttribute="trailing" constant="-10" id="c3P-Ma-Ocm"/>
|
||||
<constraint firstItem="wV9-qB-JGb" firstAttribute="leading" secondItem="vDv-xW-x2P" secondAttribute="trailing" constant="15" id="vsh-yU-UTb"/>
|
||||
<constraint firstItem="vDv-xW-x2P" firstAttribute="leading" secondItem="lk5-Bh-v0N" secondAttribute="leading" constant="8" id="xsT-ae-8gw"/>
|
||||
<constraint firstAttribute="trailing" secondItem="wV9-qB-JGb" secondAttribute="trailing" constant="20" id="zOI-eo-Njv"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IDf-Id-7mu">
|
||||
<rect key="frame" x="12" y="240" width="351" height="40"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="nhD-gd-mEK">
|
||||
<rect key="frame" x="123" y="3" width="208" height="34"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="34" id="WBy-we-3OC"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="帧率:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PoZ-CC-jCb">
|
||||
<rect key="frame" x="8" y="9.5" width="100" height="21"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="100" id="gK8-UO-TtM"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="nhD-gd-mEK" firstAttribute="centerY" secondItem="IDf-Id-7mu" secondAttribute="centerY" id="6mk-CZ-OMy"/>
|
||||
<constraint firstAttribute="trailing" secondItem="nhD-gd-mEK" secondAttribute="trailing" constant="20" id="AGt-9B-Uth"/>
|
||||
<constraint firstItem="PoZ-CC-jCb" firstAttribute="centerY" secondItem="IDf-Id-7mu" secondAttribute="centerY" id="GJV-PX-CDH"/>
|
||||
<constraint firstItem="nhD-gd-mEK" firstAttribute="leading" secondItem="PoZ-CC-jCb" secondAttribute="trailing" constant="15" id="cTX-hD-ieZ"/>
|
||||
<constraint firstAttribute="height" constant="40" id="iqb-AR-1CY"/>
|
||||
<constraint firstItem="PoZ-CC-jCb" firstAttribute="leading" secondItem="IDf-Id-7mu" secondAttribute="leading" constant="8" id="pnR-GR-09Q"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="W0R-IR-lPi">
|
||||
<rect key="frame" x="12" y="285" width="351" height="40"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Tsd-Lx-MhA">
|
||||
<rect key="frame" x="123" y="3" width="208" height="34"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="34" id="OVb-Ca-khK"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="whP-gf-Uak" id="REw-rP-sGg"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="分辨率:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="llS-Ux-nrR">
|
||||
<rect key="frame" x="8" y="9.5" width="100" height="21"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="100" id="f9s-Ui-CBN"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="5pD-qS-WYg"/>
|
||||
<constraint firstItem="Tsd-Lx-MhA" firstAttribute="centerY" secondItem="W0R-IR-lPi" secondAttribute="centerY" id="HE1-D4-gJU"/>
|
||||
<constraint firstItem="llS-Ux-nrR" firstAttribute="leading" secondItem="W0R-IR-lPi" secondAttribute="leading" constant="8" id="PSf-92-xs8"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Tsd-Lx-MhA" secondAttribute="trailing" constant="20" id="Qmf-rS-vog"/>
|
||||
<constraint firstItem="Tsd-Lx-MhA" firstAttribute="leading" secondItem="llS-Ux-nrR" secondAttribute="trailing" constant="15" id="S0N-wO-UIp"/>
|
||||
<constraint firstItem="llS-Ux-nrR" firstAttribute="centerY" secondItem="W0R-IR-lPi" secondAttribute="centerY" id="c4F-6P-cML"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="L8W-Pl-Q8x">
|
||||
<rect key="frame" x="132.5" y="104" width="110" height="32"/>
|
||||
<segments>
|
||||
<segment title="RTMP"/>
|
||||
<segment title="RTC"/>
|
||||
</segments>
|
||||
</segmentedControl>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="EWP-9V-Bsd">
|
||||
<rect key="frame" x="12" y="195" width="351" height="40"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="V4F-hH-61i">
|
||||
<rect key="frame" x="123" y="3" width="208" height="34"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="34" id="t3i-qs-8TT"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="码率min:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FkW-ed-OdH">
|
||||
<rect key="frame" x="8" y="9.5" width="100" height="21"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="100" id="Jru-El-RT6"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="kbps" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lpQ-q5-iQM">
|
||||
<rect key="frame" x="289" y="11.5" width="32" height="17"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="V4F-hH-61i" firstAttribute="centerY" secondItem="EWP-9V-Bsd" secondAttribute="centerY" id="8Sn-FB-U4E"/>
|
||||
<constraint firstItem="FkW-ed-OdH" firstAttribute="centerY" secondItem="EWP-9V-Bsd" secondAttribute="centerY" id="DeN-b9-pbH"/>
|
||||
<constraint firstAttribute="trailing" secondItem="V4F-hH-61i" secondAttribute="trailing" constant="20" id="KxG-6H-Lzu"/>
|
||||
<constraint firstAttribute="height" constant="40" id="XeA-bT-1aC"/>
|
||||
<constraint firstItem="FkW-ed-OdH" firstAttribute="leading" secondItem="EWP-9V-Bsd" secondAttribute="leading" constant="8" id="Xtu-FB-uBJ"/>
|
||||
<constraint firstItem="lpQ-q5-iQM" firstAttribute="trailing" secondItem="V4F-hH-61i" secondAttribute="trailing" constant="-10" id="hq6-4f-bmZ"/>
|
||||
<constraint firstItem="lpQ-q5-iQM" firstAttribute="centerY" secondItem="EWP-9V-Bsd" secondAttribute="centerY" id="mPb-Sr-Y0e"/>
|
||||
<constraint firstItem="V4F-hH-61i" firstAttribute="leading" secondItem="FkW-ed-OdH" secondAttribute="trailing" constant="15" id="v4F-9s-PuE"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fKV-x5-bNe" customClass="SCButton">
|
||||
<rect key="frame" x="132.5" y="602" width="110" height="35"/>
|
||||
<color key="backgroundColor" red="0.47450980390000003" green="0.40000000000000002" blue="0.98039215690000003" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="110" id="Byz-FQ-xvX"/>
|
||||
<constraint firstAttribute="height" constant="35" id="H8w-CV-5oH"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="提交日志">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="uploadLog:" destination="whP-gf-Uak" eventType="touchUpInside" id="cP2-Px-jJI"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="M7B-Vk-r8H">
|
||||
<rect key="frame" x="12" y="430" width="351" height="50"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="caC-m7-cju">
|
||||
<rect key="frame" x="10" y="8" width="226" height="34"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="34" id="u8M-21-CYJ"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="A1C-Xc-X1e" customClass="SCButton">
|
||||
<rect key="frame" x="251" y="7.5" width="90" height="35"/>
|
||||
<color key="backgroundColor" red="0.47450980390000003" green="0.40000000000000002" blue="0.98039215690000003" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="90" id="S8A-ti-FPi"/>
|
||||
<constraint firstAttribute="height" constant="35" id="nm3-Es-daW"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="加入单聊">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="startP2p:" destination="whP-gf-Uak" eventType="touchUpInside" id="lo0-R7-AhM"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="A1C-Xc-X1e" firstAttribute="leading" secondItem="caC-m7-cju" secondAttribute="trailing" constant="15" id="0EG-RP-neY"/>
|
||||
<constraint firstItem="A1C-Xc-X1e" firstAttribute="centerY" secondItem="M7B-Vk-r8H" secondAttribute="centerY" id="AMn-Hd-AAk"/>
|
||||
<constraint firstAttribute="height" constant="50" id="YMq-Mw-IfH"/>
|
||||
<constraint firstAttribute="trailing" secondItem="A1C-Xc-X1e" secondAttribute="trailing" constant="10" id="gXl-DD-O9b"/>
|
||||
<constraint firstItem="caC-m7-cju" firstAttribute="centerY" secondItem="M7B-Vk-r8H" secondAttribute="centerY" id="h3O-yt-lDF"/>
|
||||
<constraint firstItem="caC-m7-cju" firstAttribute="leading" secondItem="M7B-Vk-r8H" secondAttribute="leading" constant="10" id="pUg-HS-RQ3"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="462-Sa-P7X">
|
||||
<rect key="frame" x="12" y="480" width="351" height="50"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="6qP-ZO-dWe">
|
||||
<rect key="frame" x="10" y="8" width="226" height="34"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="34" id="oIF-YU-rNd"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
</textField>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="obR-vD-TLx" customClass="SCButton">
|
||||
<rect key="frame" x="251" y="7.5" width="90" height="35"/>
|
||||
<color key="backgroundColor" red="0.47450980390000003" green="0.40000000000000002" blue="0.98039215690000003" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="35" id="5aO-q4-wlT"/>
|
||||
<constraint firstAttribute="width" constant="90" id="PIU-J6-CxF"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="加入会议">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="startConference:" destination="whP-gf-Uak" eventType="touchUpInside" id="rhj-Wd-wfQ"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="6qP-ZO-dWe" firstAttribute="leading" secondItem="462-Sa-P7X" secondAttribute="leading" constant="10" id="MaX-kN-gyG"/>
|
||||
<constraint firstAttribute="trailing" secondItem="obR-vD-TLx" secondAttribute="trailing" constant="10" id="RQw-nK-dj0"/>
|
||||
<constraint firstItem="6qP-ZO-dWe" firstAttribute="centerY" secondItem="462-Sa-P7X" secondAttribute="centerY" id="T7z-jB-rSl"/>
|
||||
<constraint firstAttribute="height" constant="50" id="krm-2O-Yfd"/>
|
||||
<constraint firstItem="obR-vD-TLx" firstAttribute="centerY" secondItem="462-Sa-P7X" secondAttribute="centerY" id="mQD-cD-tFc"/>
|
||||
<constraint firstItem="obR-vD-TLx" firstAttribute="leading" secondItem="6qP-ZO-dWe" secondAttribute="trailing" constant="15" id="znn-MK-NjE"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="lk5-Bh-v0N" secondAttribute="trailing" constant="12" id="1oM-Oi-pJd"/>
|
||||
<constraint firstItem="PrS-3B-i8N" firstAttribute="leading" secondItem="PIl-y0-S6k" secondAttribute="leading" id="32f-Zn-mK8"/>
|
||||
<constraint firstItem="PrS-3B-i8N" firstAttribute="top" secondItem="PIl-y0-S6k" secondAttribute="bottom" id="59P-OM-43D"/>
|
||||
<constraint firstItem="lk5-Bh-v0N" firstAttribute="top" secondItem="L8W-Pl-Q8x" secondAttribute="bottom" constant="15" id="7lN-ed-P4E"/>
|
||||
<constraint firstItem="EWP-9V-Bsd" firstAttribute="top" secondItem="lk5-Bh-v0N" secondAttribute="bottom" constant="5" id="84o-T9-Ogm"/>
|
||||
<constraint firstAttribute="trailing" secondItem="eNE-Sg-1oo" secondAttribute="trailing" constant="20" id="8GT-ZB-fXI"/>
|
||||
<constraint firstItem="I8T-3g-j1c" firstAttribute="leading" secondItem="TpU-gO-2f1" secondAttribute="leadingMargin" constant="10" id="8cc-E0-81K"/>
|
||||
<constraint firstItem="L8W-Pl-Q8x" firstAttribute="centerX" secondItem="TpU-gO-2f1" secondAttribute="centerX" id="9U6-uU-uqH"/>
|
||||
<constraint firstItem="W0R-IR-lPi" firstAttribute="trailing" secondItem="IDf-Id-7mu" secondAttribute="trailing" id="BYN-5i-P1r"/>
|
||||
<constraint firstItem="I8T-3g-j1c" firstAttribute="top" secondItem="uEw-UM-LJ8" secondAttribute="bottom" id="CfY-f6-d5T"/>
|
||||
<constraint firstItem="462-Sa-P7X" firstAttribute="top" secondItem="M7B-Vk-r8H" secondAttribute="bottom" id="D23-0u-Slz"/>
|
||||
<constraint firstItem="eNE-Sg-1oo" firstAttribute="centerY" secondItem="I8T-3g-j1c" secondAttribute="centerY" id="IwB-I5-eV4"/>
|
||||
<constraint firstItem="W0R-IR-lPi" firstAttribute="top" secondItem="IDf-Id-7mu" secondAttribute="bottom" constant="5" id="MS9-ax-pue"/>
|
||||
<constraint firstItem="M7B-Vk-r8H" firstAttribute="top" secondItem="PrS-3B-i8N" secondAttribute="bottom" id="OpN-9m-KH7"/>
|
||||
<constraint firstItem="lk5-Bh-v0N" firstAttribute="leading" secondItem="TpU-gO-2f1" secondAttribute="leading" constant="12" id="TdD-pw-g2U"/>
|
||||
<constraint firstItem="EWP-9V-Bsd" firstAttribute="trailing" secondItem="lk5-Bh-v0N" secondAttribute="trailing" id="UZf-Ah-NIz"/>
|
||||
<constraint firstItem="fKV-x5-bNe" firstAttribute="centerX" secondItem="TpU-gO-2f1" secondAttribute="centerX" id="XPw-pk-E92"/>
|
||||
<constraint firstItem="W0R-IR-lPi" firstAttribute="leading" secondItem="IDf-Id-7mu" secondAttribute="leading" id="akE-ZB-STU"/>
|
||||
<constraint firstItem="462-Sa-P7X" firstAttribute="trailing" secondItem="M7B-Vk-r8H" secondAttribute="trailing" id="bnI-dY-XsC"/>
|
||||
<constraint firstItem="EWP-9V-Bsd" firstAttribute="leading" secondItem="lk5-Bh-v0N" secondAttribute="leading" id="g0Z-hq-IF9"/>
|
||||
<constraint firstItem="IDf-Id-7mu" firstAttribute="top" secondItem="EWP-9V-Bsd" secondAttribute="bottom" constant="5" id="g9f-x3-ynZ"/>
|
||||
<constraint firstItem="Mvr-aV-6Um" firstAttribute="top" secondItem="fKV-x5-bNe" secondAttribute="bottom" constant="30" id="iW3-g3-CJa"/>
|
||||
<constraint firstItem="IDf-Id-7mu" firstAttribute="leading" secondItem="lk5-Bh-v0N" secondAttribute="leading" id="jJe-4U-HgE"/>
|
||||
<constraint firstItem="462-Sa-P7X" firstAttribute="leading" secondItem="M7B-Vk-r8H" secondAttribute="leading" id="jjs-bv-imv"/>
|
||||
<constraint firstItem="PIl-y0-S6k" firstAttribute="top" secondItem="W0R-IR-lPi" secondAttribute="bottom" constant="5" id="nI0-0Q-1OZ"/>
|
||||
<constraint firstItem="M7B-Vk-r8H" firstAttribute="leading" secondItem="PrS-3B-i8N" secondAttribute="leading" id="r4H-sg-BNf"/>
|
||||
<constraint firstItem="PIl-y0-S6k" firstAttribute="leading" secondItem="TpU-gO-2f1" secondAttribute="leading" constant="12" id="rJW-eq-iOY"/>
|
||||
<constraint firstItem="PrS-3B-i8N" firstAttribute="trailing" secondItem="PIl-y0-S6k" secondAttribute="trailing" id="sI6-TV-cPh"/>
|
||||
<constraint firstItem="IDf-Id-7mu" firstAttribute="trailing" secondItem="lk5-Bh-v0N" secondAttribute="trailing" id="uUs-pI-AKX"/>
|
||||
<constraint firstItem="L8W-Pl-Q8x" firstAttribute="top" secondItem="uEw-UM-LJ8" secondAttribute="bottom" constant="30" id="whd-pU-1g8"/>
|
||||
<constraint firstAttribute="trailing" secondItem="PIl-y0-S6k" secondAttribute="trailing" constant="12" id="x81-XA-O6e"/>
|
||||
<constraint firstItem="M7B-Vk-r8H" firstAttribute="trailing" secondItem="PrS-3B-i8N" secondAttribute="trailing" id="zeR-ir-QXk"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="pG4-6j-vCt"/>
|
||||
<connections>
|
||||
<outlet property="audioOnlySwi" destination="eNE-Sg-1oo" id="Whc-Eo-eZX"/>
|
||||
<outlet property="conferenceChannelTf" destination="6qP-ZO-dWe" id="5cz-xG-Ea5"/>
|
||||
<outlet property="fpsTf" destination="nhD-gd-mEK" id="MNJ-3o-e0X"/>
|
||||
<outlet property="maxBitrateTf" destination="wV9-qB-JGb" id="uix-0W-Dwd"/>
|
||||
<outlet property="minBitrateTf" destination="V4F-hH-61i" id="NoG-AV-wRo"/>
|
||||
<outlet property="p2pChannelTf" destination="caC-m7-cju" id="ars-gl-iXG"/>
|
||||
<outlet property="playNameTf" destination="oHO-o9-X3f" id="Jrr-fT-yrd"/>
|
||||
<outlet property="pushNameTf" destination="IlC-J7-Yz0" id="RAw-bw-YE8"/>
|
||||
<outlet property="seg" destination="L8W-Pl-Q8x" id="hP0-DE-j9q"/>
|
||||
<outlet property="videoSizeTf" destination="Tsd-Lx-MhA" id="gIE-Up-SaY"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="tc2-Qw-aMS" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-871.20000000000005" y="-84.107946026986511"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
26
Example/SellyCloudSDK/Controllers/AVLoginViewController.h
Normal file
26
Example/SellyCloudSDK/Controllers/AVLoginViewController.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// AVLoginViewController.h
|
||||
// AVDemo
|
||||
//
|
||||
// 登录视图控制器
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class AVLoginViewController;
|
||||
|
||||
@protocol AVLoginViewControllerDelegate <NSObject>
|
||||
@optional
|
||||
/// 登录成功回调
|
||||
- (void)loginViewControllerDidLogin:(AVLoginViewController *)controller;
|
||||
@end
|
||||
|
||||
@interface AVLoginViewController : UIViewController
|
||||
|
||||
@property (nonatomic, weak) id<AVLoginViewControllerDelegate> delegate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
295
Example/SellyCloudSDK/Controllers/AVLoginViewController.m
Normal file
295
Example/SellyCloudSDK/Controllers/AVLoginViewController.m
Normal file
@@ -0,0 +1,295 @@
|
||||
//
|
||||
// AVLoginViewController.m
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import "AVLoginViewController.h"
|
||||
#import "AVUserManager.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
|
||||
@interface AVLoginViewController () <UITextFieldDelegate>
|
||||
@property (nonatomic, strong) UIImageView *logoImageView;
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
@property (nonatomic, strong) UIView *usernameContainer;
|
||||
@property (nonatomic, strong) UITextField *usernameTextField;
|
||||
@property (nonatomic, strong) UIView *passwordContainer;
|
||||
@property (nonatomic, strong) UITextField *passwordTextField;
|
||||
@property (nonatomic, strong) UIButton *passwordToggleButton;
|
||||
@property (nonatomic, strong) UIButton *loginButton;
|
||||
@end
|
||||
|
||||
@implementation AVLoginViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.view.backgroundColor = [UIColor systemBackgroundColor];
|
||||
|
||||
[self setupUI];
|
||||
[self loadSavedUsername];
|
||||
|
||||
// 添加点击手势,点击空白处收起键盘
|
||||
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
|
||||
[self.view addGestureRecognizer:tapGesture];
|
||||
}
|
||||
|
||||
- (void)setupUI {
|
||||
// Logo 图标
|
||||
self.logoImageView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"play.rectangle.on.rectangle.fill"]];
|
||||
self.logoImageView.tintColor = [UIColor systemBlueColor];
|
||||
self.logoImageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
[self.view addSubview:self.logoImageView];
|
||||
|
||||
[self.logoImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.equalTo(self.view);
|
||||
make.top.equalTo(self.view.mas_safeAreaLayoutGuideTop).offset(80);
|
||||
make.width.height.equalTo(@100);
|
||||
}];
|
||||
|
||||
// 标题
|
||||
self.titleLabel = [[UILabel alloc] init];
|
||||
self.titleLabel.text = @"欢迎使用";
|
||||
self.titleLabel.font = [UIFont systemFontOfSize:28 weight:UIFontWeightBold];
|
||||
self.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
[self.view addSubview:self.titleLabel];
|
||||
|
||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.equalTo(self.view);
|
||||
make.top.equalTo(self.logoImageView.mas_bottom).offset(24);
|
||||
}];
|
||||
|
||||
// 用户名输入框容器
|
||||
self.usernameContainer = [[UIView alloc] init];
|
||||
self.usernameContainer.backgroundColor = [UIColor secondarySystemBackgroundColor];
|
||||
self.usernameContainer.layer.cornerRadius = 12;
|
||||
[self.view addSubview:self.usernameContainer];
|
||||
|
||||
[self.usernameContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.equalTo(self.view);
|
||||
make.top.equalTo(self.titleLabel.mas_bottom).offset(60);
|
||||
make.left.equalTo(self.view).offset(32);
|
||||
make.right.equalTo(self.view).offset(-32);
|
||||
make.height.equalTo(@50);
|
||||
}];
|
||||
|
||||
// 用户名图标
|
||||
UIImageView *usernameIcon = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"person.fill"]];
|
||||
usernameIcon.tintColor = [UIColor systemGrayColor];
|
||||
usernameIcon.contentMode = UIViewContentModeScaleAspectFit;
|
||||
[self.usernameContainer addSubview:usernameIcon];
|
||||
|
||||
[usernameIcon mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.usernameContainer).offset(16);
|
||||
make.centerY.equalTo(self.usernameContainer);
|
||||
make.width.height.equalTo(@20);
|
||||
}];
|
||||
|
||||
// 用户名输入框
|
||||
self.usernameTextField = [[UITextField alloc] init];
|
||||
self.usernameTextField.placeholder = @"请输入用户名";
|
||||
self.usernameTextField.font = [UIFont systemFontOfSize:16];
|
||||
self.usernameTextField.returnKeyType = UIReturnKeyNext;
|
||||
self.usernameTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
self.usernameTextField.autocorrectionType = UITextAutocorrectionTypeNo;
|
||||
self.usernameTextField.delegate = self;
|
||||
[self.usernameContainer addSubview:self.usernameTextField];
|
||||
|
||||
[self.usernameTextField mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(usernameIcon.mas_right).offset(12);
|
||||
make.right.equalTo(self.usernameContainer).offset(-16);
|
||||
make.centerY.equalTo(self.usernameContainer);
|
||||
}];
|
||||
|
||||
// 密码输入框容器
|
||||
self.passwordContainer = [[UIView alloc] init];
|
||||
self.passwordContainer.backgroundColor = [UIColor secondarySystemBackgroundColor];
|
||||
self.passwordContainer.layer.cornerRadius = 12;
|
||||
[self.view addSubview:self.passwordContainer];
|
||||
|
||||
[self.passwordContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.equalTo(self.view);
|
||||
make.top.equalTo(self.usernameContainer.mas_bottom).offset(16);
|
||||
make.left.equalTo(self.view).offset(32);
|
||||
make.right.equalTo(self.view).offset(-32);
|
||||
make.height.equalTo(@50);
|
||||
}];
|
||||
|
||||
// 密码图标
|
||||
UIImageView *passwordIcon = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"lock.fill"]];
|
||||
passwordIcon.tintColor = [UIColor systemGrayColor];
|
||||
passwordIcon.contentMode = UIViewContentModeScaleAspectFit;
|
||||
[self.passwordContainer addSubview:passwordIcon];
|
||||
|
||||
[passwordIcon mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.passwordContainer).offset(16);
|
||||
make.centerY.equalTo(self.passwordContainer);
|
||||
make.width.height.equalTo(@20);
|
||||
}];
|
||||
|
||||
// 密码输入框
|
||||
self.passwordTextField = [[UITextField alloc] init];
|
||||
self.passwordTextField.placeholder = @"请输入密码";
|
||||
self.passwordTextField.font = [UIFont systemFontOfSize:16];
|
||||
self.passwordTextField.secureTextEntry = YES;
|
||||
self.passwordTextField.returnKeyType = UIReturnKeyDone;
|
||||
self.passwordTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
self.passwordTextField.autocorrectionType = UITextAutocorrectionTypeNo;
|
||||
self.passwordTextField.delegate = self;
|
||||
[self.passwordContainer addSubview:self.passwordTextField];
|
||||
|
||||
// 密码显示/隐藏切换按钮
|
||||
self.passwordToggleButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[self.passwordToggleButton setImage:[UIImage systemImageNamed:@"eye.slash.fill"] forState:UIControlStateNormal];
|
||||
[self.passwordToggleButton setImage:[UIImage systemImageNamed:@"eye.fill"] forState:UIControlStateSelected];
|
||||
self.passwordToggleButton.tintColor = [UIColor systemGrayColor];
|
||||
[self.passwordToggleButton addTarget:self action:@selector(togglePasswordVisibility) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self.passwordContainer addSubview:self.passwordToggleButton];
|
||||
|
||||
[self.passwordToggleButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.passwordContainer).offset(-16);
|
||||
make.centerY.equalTo(self.passwordContainer);
|
||||
make.width.height.equalTo(@24);
|
||||
}];
|
||||
|
||||
[self.passwordTextField mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(passwordIcon.mas_right).offset(12);
|
||||
make.right.equalTo(self.passwordToggleButton.mas_left).offset(-12);
|
||||
make.centerY.equalTo(self.passwordContainer);
|
||||
}];
|
||||
|
||||
// 登录按钮
|
||||
self.loginButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
[self.loginButton setTitle:@"登录" forState:UIControlStateNormal];
|
||||
self.loginButton.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold];
|
||||
self.loginButton.backgroundColor = [UIColor systemBlueColor];
|
||||
[self.loginButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
self.loginButton.layer.cornerRadius = 12;
|
||||
[self.loginButton addTarget:self action:@selector(loginButtonTapped) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self.view addSubview:self.loginButton];
|
||||
|
||||
[self.loginButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.equalTo(self.view);
|
||||
make.top.equalTo(self.passwordContainer.mas_bottom).offset(32);
|
||||
make.left.equalTo(self.view).offset(32);
|
||||
make.right.equalTo(self.view).offset(-32);
|
||||
make.height.equalTo(@50);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)loadSavedUsername {
|
||||
// 从 AVUserManager 获取上次登录的用户名
|
||||
NSString *savedUsername = [AVUserManager sharedManager].currentUsername;
|
||||
|
||||
if (savedUsername.length > 0) {
|
||||
self.usernameTextField.text = savedUsername;
|
||||
NSLog(@"✅ 自动填充用户名: %@", savedUsername);
|
||||
|
||||
// 如果有保存的用户名,自动聚焦到密码输入框
|
||||
[self.passwordTextField becomeFirstResponder];
|
||||
} else {
|
||||
// 如果没有保存的用户名,聚焦到用户名输入框
|
||||
[self.usernameTextField becomeFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)loginButtonTapped {
|
||||
[self dismissKeyboard];
|
||||
|
||||
NSString *username = self.usernameTextField.text;
|
||||
NSString *password = self.passwordTextField.text;
|
||||
|
||||
// 验证输入
|
||||
if (username.length == 0) {
|
||||
[self showAlertWithMessage:@"请输入用户名"];
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.length == 0) {
|
||||
[self showAlertWithMessage:@"请输入密码"];
|
||||
return;
|
||||
}
|
||||
|
||||
// 禁用登录按钮,防止重复提交
|
||||
self.loginButton.enabled = NO;
|
||||
[self.loginButton setTitle:@"登录中..." forState:UIControlStateNormal];
|
||||
self.loginButton.alpha = 0.6;
|
||||
|
||||
// 执行登录(异步)
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[[AVUserManager sharedManager] loginWithUsername:username password:password completion:^(BOOL success, NSString * _Nullable errorMessage) {
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
if (!strongSelf) return;
|
||||
|
||||
// 恢复登录按钮状态
|
||||
strongSelf.loginButton.enabled = YES;
|
||||
[strongSelf.loginButton setTitle:@"登录" forState:UIControlStateNormal];
|
||||
strongSelf.loginButton.alpha = 1.0;
|
||||
|
||||
if (success) {
|
||||
// 登录成功,通知代理
|
||||
NSLog(@"✅ 登录验证成功");
|
||||
if ([strongSelf.delegate respondsToSelector:@selector(loginViewControllerDidLogin:)]) {
|
||||
[strongSelf.delegate loginViewControllerDidLogin:strongSelf];
|
||||
}
|
||||
} else {
|
||||
// 登录失败,显示错误信息
|
||||
NSLog(@"❌ 登录验证失败: %@", errorMessage);
|
||||
[strongSelf showAlertWithMessage:errorMessage ?: @"登录失败,请重试"];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard {
|
||||
[self.view endEditing:YES];
|
||||
}
|
||||
|
||||
- (void)togglePasswordVisibility {
|
||||
// 切换密码的可见性
|
||||
self.passwordTextField.secureTextEntry = !self.passwordTextField.secureTextEntry;
|
||||
|
||||
// 切换按钮状态
|
||||
self.passwordToggleButton.selected = !self.passwordToggleButton.selected;
|
||||
|
||||
// 保持光标位置(修复切换时光标跳到开头的问题)
|
||||
NSString *currentText = self.passwordTextField.text;
|
||||
self.passwordTextField.text = @"";
|
||||
self.passwordTextField.text = currentText;
|
||||
}
|
||||
|
||||
- (void)showAlertWithMessage:(NSString *)message {
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示"
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
if (textField == self.usernameTextField) {
|
||||
// 用户名输入框按回车,跳到密码输入框
|
||||
[self.passwordTextField becomeFirstResponder];
|
||||
} else if (textField == self.passwordTextField) {
|
||||
// 密码输入框按回车,执行登录
|
||||
[self loginButtonTapped];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Orientation Support
|
||||
|
||||
- (BOOL)shouldAutorotate {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
return UIInterfaceOrientationPortrait;
|
||||
}
|
||||
|
||||
@end
|
||||
14
Example/SellyCloudSDK/Controllers/AVTabBarController.h
Normal file
14
Example/SellyCloudSDK/Controllers/AVTabBarController.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// AVTabBarController.h
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AVTabBarController : UITabBarController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
114
Example/SellyCloudSDK/Controllers/AVTabBarController.m
Normal file
114
Example/SellyCloudSDK/Controllers/AVTabBarController.m
Normal file
@@ -0,0 +1,114 @@
|
||||
//
|
||||
// AVTabBarController.m
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import "AVTabBarController.h"
|
||||
#import "AVHomeViewController.h"
|
||||
#import "AVCallViewController.h"
|
||||
#import "AVSettingsViewController.h"
|
||||
#import "AVLoginViewController.h"
|
||||
#import "AVUserManager.h"
|
||||
|
||||
@interface AVTabBarController () <AVLoginViewControllerDelegate>
|
||||
@end
|
||||
|
||||
@implementation AVTabBarController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// Create Home tab
|
||||
AVHomeViewController *homeVC = [[AVHomeViewController alloc] init];
|
||||
UINavigationController *homeNav = [[UINavigationController alloc] initWithRootViewController:homeVC];
|
||||
homeNav.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"首页"
|
||||
image:[UIImage systemImageNamed:@"house"]
|
||||
selectedImage:[UIImage systemImageNamed:@"house.fill"]];
|
||||
|
||||
// Create Call tab
|
||||
AVCallViewController *callVC = [[AVCallViewController alloc] init];
|
||||
UINavigationController *callNav = [[UINavigationController alloc] initWithRootViewController:callVC];
|
||||
callNav.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"通话"
|
||||
image:[UIImage systemImageNamed:@"phone"]
|
||||
selectedImage:[UIImage systemImageNamed:@"phone.fill"]];
|
||||
|
||||
// Create Settings tab
|
||||
AVSettingsViewController *settingsVC = [[AVSettingsViewController alloc] init];
|
||||
UINavigationController *settingsNav = [[UINavigationController alloc] initWithRootViewController:settingsVC];
|
||||
settingsNav.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"设置"
|
||||
image:[UIImage systemImageNamed:@"gearshape"]
|
||||
selectedImage:[UIImage systemImageNamed:@"gearshape.fill"]];
|
||||
|
||||
// Set view controllers
|
||||
self.viewControllers = @[homeNav, callNav, settingsNav];
|
||||
|
||||
// Customize tab bar appearance
|
||||
self.tabBar.tintColor = [UIColor systemBlueColor];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
// 检查登录状态
|
||||
[self checkLoginStatus];
|
||||
}
|
||||
|
||||
#pragma mark - Login Management
|
||||
|
||||
- (void)checkLoginStatus {
|
||||
// 如果未登录,显示登录页面
|
||||
if (![AVUserManager sharedManager].isLoggedIn) {
|
||||
[self showLoginViewController];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showLoginViewController {
|
||||
AVLoginViewController *loginVC = [[AVLoginViewController alloc] init];
|
||||
loginVC.delegate = self;
|
||||
loginVC.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
|
||||
// 确保不会重复弹出登录页面
|
||||
if (self.presentedViewController == nil) {
|
||||
[self presentViewController:loginVC animated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - AVLoginViewControllerDelegate
|
||||
|
||||
- (void)loginViewControllerDidLogin:(AVLoginViewController *)controller {
|
||||
// 登录成功,关闭登录页面
|
||||
[controller dismissViewControllerAnimated:YES completion:^{
|
||||
NSLog(@"✅ 登录成功,已进入应用");
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Orientation Support (将方向决策交给顶层 ViewController)
|
||||
|
||||
- (BOOL)shouldAutorotate {
|
||||
// 返回当前显示的 NavigationController 的顶层 VC 的设置
|
||||
UINavigationController *nav = (UINavigationController *)self.selectedViewController;
|
||||
if ([nav isKindOfClass:[UINavigationController class]]) {
|
||||
return [nav.topViewController shouldAutorotate];
|
||||
}
|
||||
return [self.selectedViewController shouldAutorotate];
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
// 返回当前显示的 NavigationController 的顶层 VC 的设置
|
||||
UINavigationController *nav = (UINavigationController *)self.selectedViewController;
|
||||
if ([nav isKindOfClass:[UINavigationController class]]) {
|
||||
return [nav.topViewController supportedInterfaceOrientations];
|
||||
}
|
||||
return [self.selectedViewController supportedInterfaceOrientations];
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
// 返回当前显示的 NavigationController 的顶层 VC 的设置
|
||||
UINavigationController *nav = (UINavigationController *)self.selectedViewController;
|
||||
if ([nav isKindOfClass:[UINavigationController class]]) {
|
||||
return [nav.topViewController preferredInterfaceOrientationForPresentation];
|
||||
}
|
||||
return [self.selectedViewController preferredInterfaceOrientationForPresentation];
|
||||
}
|
||||
|
||||
@end
|
||||
36
Example/SellyCloudSDK/Controllers/AVUserManager.h
Normal file
36
Example/SellyCloudSDK/Controllers/AVUserManager.h
Normal file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// AVUserManager.h
|
||||
// AVDemo
|
||||
//
|
||||
// 用户管理类 - 管理用户登录状态
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AVUserManager : NSObject
|
||||
|
||||
/// 单例
|
||||
+ (instancetype)sharedManager;
|
||||
|
||||
/// 检查用户是否已登录
|
||||
@property (nonatomic, assign, readonly) BOOL isLoggedIn;
|
||||
|
||||
/// 当前用户名(可选)
|
||||
@property (nonatomic, copy, nullable) NSString *currentUsername;
|
||||
|
||||
/// 登录(异步,带回调)
|
||||
/// @param username 用户名
|
||||
/// @param password 密码
|
||||
/// @param completion 完成回调,success 表示是否成功,errorMessage 为错误信息(成功时为 nil)
|
||||
- (void)loginWithUsername:(NSString *)username
|
||||
password:(NSString *)password
|
||||
completion:(void (^)(BOOL success, NSString * _Nullable errorMessage))completion;
|
||||
|
||||
/// 登出
|
||||
- (void)logout;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
151
Example/SellyCloudSDK/Controllers/AVUserManager.m
Normal file
151
Example/SellyCloudSDK/Controllers/AVUserManager.m
Normal file
@@ -0,0 +1,151 @@
|
||||
//
|
||||
// AVUserManager.m
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import "AVUserManager.h"
|
||||
#import <AFNetworking/AFNetworking.h>
|
||||
|
||||
static NSString * const kUserLoggedInKey = @"AVUserLoggedIn";
|
||||
static NSString * const kUserUsernameKey = @"AVUserUsername";
|
||||
|
||||
@interface AVUserManager ()
|
||||
@property (nonatomic, strong) AFHTTPSessionManager *sessionManager;
|
||||
@end
|
||||
|
||||
@implementation AVUserManager
|
||||
|
||||
+ (instancetype)sharedManager {
|
||||
static AVUserManager *instance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[self alloc] init];
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
// 从 UserDefaults 读取登录状态
|
||||
_isLoggedIn = [[NSUserDefaults standardUserDefaults] boolForKey:kUserLoggedInKey];
|
||||
_currentUsername = [[NSUserDefaults standardUserDefaults] stringForKey:kUserUsernameKey];
|
||||
|
||||
// 初始化网络请求管理器
|
||||
self.sessionManager = [AFHTTPSessionManager manager];
|
||||
self.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
|
||||
self.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
|
||||
self.sessionManager.requestSerializer.timeoutInterval = 10;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loginWithUsername:(NSString *)username
|
||||
password:(NSString *)password
|
||||
completion:(void (^)(BOOL success, NSString * _Nullable errorMessage))completion {
|
||||
|
||||
// 基本参数验证
|
||||
if (username.length == 0) {
|
||||
if (completion) {
|
||||
completion(NO, @"用户名不能为空");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.length == 0) {
|
||||
if (completion) {
|
||||
completion(NO, @"密码不能为空");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 登录 API 端点
|
||||
NSString *loginURL = @"http://rtmp.sellycloud.io:8089/live/sdk/demo/login";
|
||||
|
||||
// 请求参数
|
||||
NSDictionary *parameters = @{
|
||||
@"username": username,
|
||||
@"password": password
|
||||
};
|
||||
|
||||
NSLog(@"🚀 开始登录请求: %@", username);
|
||||
|
||||
// 发起 POST 请求
|
||||
[self.sessionManager POST:loginURL parameters:parameters headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
// 登录成功
|
||||
NSLog(@"✅ 登录成功,服务器响应: %@", responseObject);
|
||||
|
||||
// 保存登录状态
|
||||
[self saveLoginStateWithUsername:username];
|
||||
|
||||
// 可以根据需要保存服务器返回的其他信息(如 token、userId 等)
|
||||
// 例如:
|
||||
// if (responseObject[@"token"]) {
|
||||
// [[NSUserDefaults standardUserDefaults] setObject:responseObject[@"token"] forKey:@"AVUserToken"];
|
||||
// }
|
||||
|
||||
// 回调成功
|
||||
if (completion) {
|
||||
completion(YES, nil);
|
||||
}
|
||||
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
// 登录失败
|
||||
NSLog(@"❌ 登录失败: %@", error.localizedDescription);
|
||||
|
||||
NSString *errorMessage = @"登录失败,请检查用户名和密码";
|
||||
|
||||
// 尝试获取 HTTP 状态码
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
|
||||
if (httpResponse) {
|
||||
NSLog(@"❌ HTTP 状态码: %ld", (long)httpResponse.statusCode);
|
||||
}
|
||||
|
||||
// 尝试解析服务器返回的错误信息
|
||||
if (error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]) {
|
||||
NSData *errorData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
|
||||
NSDictionary *errorDict = [NSJSONSerialization JSONObjectWithData:errorData options:0 error:nil];
|
||||
|
||||
NSLog(@"❌ 服务器错误响应: %@", errorDict);
|
||||
|
||||
// 尝试多种可能的错误信息字段
|
||||
if (errorDict[@"message"]) {
|
||||
errorMessage = errorDict[@"message"];
|
||||
} else if (errorDict[@"error"]) {
|
||||
errorMessage = errorDict[@"error"];
|
||||
} else if (errorDict[@"msg"]) {
|
||||
errorMessage = errorDict[@"msg"];
|
||||
}
|
||||
} else {
|
||||
// 网络错误
|
||||
errorMessage = [NSString stringWithFormat:@"网络请求失败: %@", error.localizedDescription];
|
||||
}
|
||||
|
||||
// 回调失败
|
||||
if (completion) {
|
||||
completion(NO, errorMessage);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)saveLoginStateWithUsername:(NSString *)username {
|
||||
_isLoggedIn = YES;
|
||||
_currentUsername = username;
|
||||
|
||||
// 持久化保存
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:kUserLoggedInKey];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:username forKey:kUserUsernameKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (void)logout {
|
||||
_isLoggedIn = NO;
|
||||
|
||||
// 清除持久化数据
|
||||
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:kUserLoggedInKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
NSLog(@"✅ 用户已登出");
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// AVCallViewController.h
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AVCallViewController : UIViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
223
Example/SellyCloudSDK/Controllers/Home/AVCallViewController.m
Normal file
223
Example/SellyCloudSDK/Controllers/Home/AVCallViewController.m
Normal file
@@ -0,0 +1,223 @@
|
||||
//
|
||||
// AVCallViewController.m
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import "AVCallViewController.h"
|
||||
#import "SellyVideoCallViewController.h"
|
||||
#import "SellyVideoCallConferenceController.h"
|
||||
#import "AVConfigManager.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
|
||||
@interface AVCallViewController () <UITextFieldDelegate>
|
||||
@property (nonatomic, strong) UITextField *channelIdTextField;
|
||||
@property (nonatomic, strong) UIButton *callButton;
|
||||
@property (nonatomic, strong) UIButton *conferenceButton;
|
||||
@property (nonatomic, strong) UIView *containerView;
|
||||
@end
|
||||
|
||||
@implementation AVCallViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.view.backgroundColor = [UIColor systemBackgroundColor];
|
||||
self.title = @"通话";
|
||||
|
||||
[self setupUI];
|
||||
|
||||
// 加载上次使用的频道ID(优先使用单聊的,如果没有则使用会议的)
|
||||
NSString *lastChannelId = [[AVConfigManager sharedManager] loadCallChannelId];
|
||||
if (lastChannelId.length == 0) {
|
||||
lastChannelId = [[AVConfigManager sharedManager] loadConferenceChannelId];
|
||||
}
|
||||
self.channelIdTextField.text = lastChannelId;
|
||||
}
|
||||
|
||||
- (void)setupUI {
|
||||
// 创建容器视图
|
||||
self.containerView = [[UIView alloc] init];
|
||||
[self.view addSubview:self.containerView];
|
||||
|
||||
// 创建频道ID标签
|
||||
UILabel *titleLabel = [[UILabel alloc] init];
|
||||
titleLabel.text = @"频道ID";
|
||||
titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
|
||||
titleLabel.textColor = [UIColor labelColor];
|
||||
[self.containerView addSubview:titleLabel];
|
||||
|
||||
// 创建频道ID输入框
|
||||
self.channelIdTextField = [[UITextField alloc] init];
|
||||
self.channelIdTextField.placeholder = @"请输入频道ID";
|
||||
self.channelIdTextField.borderStyle = UITextBorderStyleRoundedRect;
|
||||
self.channelIdTextField.font = [UIFont systemFontOfSize:16];
|
||||
self.channelIdTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
|
||||
self.channelIdTextField.returnKeyType = UIReturnKeyDone;
|
||||
self.channelIdTextField.delegate = self;
|
||||
self.channelIdTextField.backgroundColor = [UIColor secondarySystemBackgroundColor];
|
||||
[self.containerView addSubview:self.channelIdTextField];
|
||||
|
||||
// 创建音视频单聊按钮
|
||||
self.callButton = [self createButtonWithTitle:@"音视频单聊"
|
||||
icon:@"video"
|
||||
action:@selector(callTapped)];
|
||||
[self.containerView addSubview:self.callButton];
|
||||
|
||||
// 创建音视频会议按钮
|
||||
self.conferenceButton = [self createButtonWithTitle:@"音视频会议"
|
||||
icon:@"person.3"
|
||||
action:@selector(conferenceTapped)];
|
||||
[self.containerView addSubview:self.conferenceButton];
|
||||
|
||||
// 布局
|
||||
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.equalTo(self.view);
|
||||
make.width.equalTo(@320);
|
||||
}];
|
||||
|
||||
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.left.equalTo(self.containerView);
|
||||
make.right.equalTo(self.containerView);
|
||||
}];
|
||||
|
||||
[self.channelIdTextField mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(titleLabel.mas_bottom).offset(8);
|
||||
make.left.right.equalTo(self.containerView);
|
||||
make.height.equalTo(@44);
|
||||
}];
|
||||
|
||||
[self.callButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.channelIdTextField.mas_bottom).offset(32);
|
||||
make.left.right.equalTo(self.containerView);
|
||||
make.height.equalTo(@100);
|
||||
}];
|
||||
|
||||
[self.conferenceButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.callButton.mas_bottom).offset(16);
|
||||
make.left.right.equalTo(self.containerView);
|
||||
make.height.equalTo(@100);
|
||||
make.bottom.equalTo(self.containerView);
|
||||
}];
|
||||
}
|
||||
|
||||
- (UIButton *)createButtonWithTitle:(NSString *)title icon:(NSString *)iconName action:(SEL)action {
|
||||
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
button.backgroundColor = [UIColor systemBlueColor];
|
||||
button.layer.cornerRadius = 12;
|
||||
button.clipsToBounds = YES;
|
||||
|
||||
// 创建图标
|
||||
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:iconName]];
|
||||
iconView.tintColor = [UIColor whiteColor];
|
||||
iconView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
|
||||
// 创建标题
|
||||
UILabel *titleLabel = [[UILabel alloc] init];
|
||||
titleLabel.text = title;
|
||||
titleLabel.textColor = [UIColor whiteColor];
|
||||
titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold];
|
||||
titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
|
||||
[button addSubview:iconView];
|
||||
[button addSubview:titleLabel];
|
||||
|
||||
[iconView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.equalTo(button);
|
||||
make.centerY.equalTo(button).offset(-15);
|
||||
make.width.height.equalTo(@40);
|
||||
}];
|
||||
|
||||
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.equalTo(button);
|
||||
make.top.equalTo(iconView.mas_bottom).offset(8);
|
||||
make.left.greaterThanOrEqualTo(button).offset(8);
|
||||
make.right.lessThanOrEqualTo(button).offset(-8);
|
||||
}];
|
||||
|
||||
[button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
#pragma mark - Button Actions
|
||||
|
||||
- (void)callTapped {
|
||||
NSString *channelId = [self.channelIdTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
|
||||
// 验证输入
|
||||
if (channelId.length == 0) {
|
||||
[self showErrorAlert:@"频道ID不能为空"];
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存频道 ID
|
||||
[[AVConfigManager sharedManager] saveCallChannelId:channelId];
|
||||
|
||||
// 创建并跳转到视频通话页面
|
||||
SellyVideoCallViewController *vc = [[SellyVideoCallViewController alloc] init];
|
||||
vc.channelId = channelId;
|
||||
vc.videoConfig = SellyRTCVideoConfiguration.defaultConfig;
|
||||
|
||||
// 隐藏底部 TabBar
|
||||
vc.hidesBottomBarWhenPushed = YES;
|
||||
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
- (void)conferenceTapped {
|
||||
NSString *channelId = [self.channelIdTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
|
||||
// 验证输入
|
||||
if (channelId.length == 0) {
|
||||
[self showErrorAlert:@"频道ID不能为空"];
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存频道 ID
|
||||
[[AVConfigManager sharedManager] saveConferenceChannelId:channelId];
|
||||
|
||||
// 创建并跳转到视频会议页面
|
||||
SellyVideoCallConferenceController *vc = [[SellyVideoCallConferenceController alloc] init];
|
||||
vc.channelId = channelId;
|
||||
vc.videoConfig = SellyRTCVideoConfiguration.defaultConfig;
|
||||
|
||||
// 隐藏底部 TabBar
|
||||
vc.hidesBottomBarWhenPushed = YES;
|
||||
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
- (void)showErrorAlert:(NSString *)message {
|
||||
UIAlertController *errorAlert = [UIAlertController alertControllerWithTitle:@"错误"
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:nil];
|
||||
[errorAlert addAction:okAction];
|
||||
[self presentViewController:errorAlert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
[textField resignFirstResponder];
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Orientation Support (强制只支持竖屏)
|
||||
|
||||
- (BOOL)shouldAutorotate {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
return UIInterfaceOrientationPortrait;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// AVHomeViewController.h
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AVHomeViewController : UIViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
393
Example/SellyCloudSDK/Controllers/Home/AVHomeViewController.m
Normal file
393
Example/SellyCloudSDK/Controllers/Home/AVHomeViewController.m
Normal file
@@ -0,0 +1,393 @@
|
||||
//
|
||||
// AVHomeViewController.m
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import "AVHomeViewController.h"
|
||||
#import "SCLivePusherViewController.h"
|
||||
#import "SCLiveVideoPlayerViewController.h"
|
||||
#import "SCVodVideoPlayerViewController.h"
|
||||
#import "AVConfigManager.h"
|
||||
#import "AVConstants.h"
|
||||
#import "AVLiveStreamModel.h"
|
||||
#import "AVLiveStreamCell.h"
|
||||
#import "SCPlayerConfigView.h"
|
||||
#import <AFNetworking/AFNetworking.h>
|
||||
#import <AFNetworking/UIImageView+AFNetworking.h>
|
||||
#import <YYModel/YYModel.h>
|
||||
|
||||
@interface AVHomeViewController () <UICollectionViewDelegate, UICollectionViewDataSource>
|
||||
@property (nonatomic, strong) UIView *headerView;
|
||||
@property (nonatomic, strong) NSArray<UIButton *> *headerButtons;
|
||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||
@property (nonatomic, strong) NSArray<AVLiveStreamModel *> *liveStreams;
|
||||
@property (nonatomic, strong) UIRefreshControl *refreshControl;
|
||||
@property (nonatomic, strong) AFHTTPSessionManager *sessionManager;
|
||||
@end
|
||||
|
||||
@implementation AVHomeViewController
|
||||
|
||||
static NSString * const kLiveStreamCellIdentifier = @"LiveStreamCell";
|
||||
static NSString * const kLiveListAPIURL = @"http://rtmp.sellycloud.io:8089/live/sdk/alive-list";
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.view.backgroundColor = [UIColor systemBackgroundColor];
|
||||
self.title = @"首页";
|
||||
|
||||
const char *kiwiAppkey = "5XTXUZ/aqOwfjA4zQkY7VpjcNBucWxmNGY4vFNhwSMKWkn2WK383dbNgI+96Y+ttSPMFzqhu8fxP5SiCK5+/6cGrBQQt8pDQAOi3EN4Z6lzkC2cJ5mfjBVi4ZpFASG9e3divF5UqLG6sTmFI3eCuJxy9/kHXPSSkKWJe1MnBMQETpf4FRDVuR9d/LzXKQgA9PsjRbPRLx4f3h0TU2P4GEfv1c70FvkdwpqirQt9ik2hAhKuj0vJY60g+yYhGY19a07vBTW4MprN53RnSH8bCs79NNbWyzsg2++t+sKdZP1WPGeOho/xpsQRP8yWCXIOOdvdjiE3YXVltBgmPnA6gOjFS97WVlBAQ1mJE7rQi+/5hhfTuJlWoBH6000SRe7dc5EA0WGQX9U1Aj96ahBQhyHTrHJySmJ/hRMYMudqByF6K4PtrwZ8zugTjtx1dyLPOonZDlTu7hPAIcUfuaQ9xS3Phbq8lP67EYDsr3pkWuwL6AjrPjFwNmi0P1g+hV1ZQUmDQVGhNHmF3cE9Pd5ZOS10/fwaXYGRhcq9PlUSmcbU3scLtrBlzpOslyjlQ6W57EudCrvvJU3mimfs1A2y7cjpnLlJN1CWh6dQAaGcwSG2QA8+88qmlMH1t627fItTgHYrP1DkExpAr2dqgYDvsICJnHaRSBMe608GrPbFaECutRz5y3BEtQKcVKdgA1e6W4TFnxs5HqGrzc8iHPOOKGf8zHWEXkITPBKEiA86Nz46pDrqM9FKx4upPijn4Dahj8pd7yWTUIdHBT8X39Vm3/TSV5xT/lTinmv8rhBieb/2SQamTjVQ22VFq3nQ1h4TxUYTEc0nSjqcz54fWf1cyBy7uh82q1weKXUAJ8vG9W05vmt3/aDZ9+C8cWm53AQ90xgDvW7M1mZveuyfof2qrPsXTpj+jhpDkJgm6qJsvV5ClmGth8gvCM0rHjSIwxhYDZaIDK5TkFWjwLltt+YhhYLKketwuTHdlO/hCxrsFzlXHhXGVRC+kgXusfQUrHIm1WjW9o9EqasHg9ufUgg7cMO/9FRZhJ+Xdw9erprYDvu84Da9jL6NUUOSNIGTCJ/s29Lz4SIwCVG2lzm2UhD6E9ipGfG9gc6e/2vt1emOsP3/ipHVJf16r/9S4+dGKIjPX6QcHIIL2AMu2Je07nPmEoz7KaeOShox4bG3puMQdkdQo6kRIFpUzwUty+4EWqHmyPHGkGGGfI8gj0EreiZwgVJmBQ/8S5wlK+iUp+TVeoXo=";
|
||||
[SellyCloudManager.sharedInstance startWithVHost:V_HOST appName:APP_ID];
|
||||
//初始化洋葱盾相关
|
||||
[SellyCloudManager setKiwiAppKey:kiwiAppkey name:"123"];
|
||||
|
||||
// 生成随机 userId: user + 3位随机数字 (001-999)
|
||||
NSInteger randomNum = arc4random_uniform(999) + 1; // 生成 1-999 的随机数
|
||||
SellyCloudManager.sharedInstance.userId = [NSString stringWithFormat:@"user%03ld", (long)randomNum]; // %03ld 保证3位数,不足补0
|
||||
|
||||
// 初始化数据
|
||||
self.liveStreams = [NSMutableArray array];
|
||||
|
||||
// 设置 AFNetworking
|
||||
self.sessionManager = [AFHTTPSessionManager manager];
|
||||
self.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
|
||||
self.sessionManager.requestSerializer.timeoutInterval = 10;
|
||||
|
||||
[self setupHeaderButtons];
|
||||
[self setupCollectionView];
|
||||
|
||||
// 首次加载数据
|
||||
[self fetchLiveStreams];
|
||||
}
|
||||
|
||||
- (void)viewWillLayoutSubviews {
|
||||
[super viewWillLayoutSubviews];
|
||||
// CollectionView 会自动根据 layout 调整
|
||||
}
|
||||
|
||||
#pragma mark - Setup UI
|
||||
|
||||
- (void)setupHeaderButtons {
|
||||
// Create 2 feature buttons
|
||||
NSArray *buttonConfigs = @[
|
||||
@{@"title": @"开始直播", @"icon": @"antenna.radiowaves.left.and.right", @"action": @"livePushTapped"},
|
||||
@{@"title": @"自定义播放", @"icon": @"play.rectangle", @"action": @"livePullTapped"}
|
||||
];
|
||||
|
||||
// 创建 header 容器 View
|
||||
self.headerView = [[UIView alloc] init];
|
||||
self.headerView.backgroundColor = [UIColor systemBackgroundColor];
|
||||
[self.view addSubview:self.headerView];
|
||||
|
||||
[self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.view.mas_safeAreaLayoutGuideTop);
|
||||
make.left.right.equalTo(self.view);
|
||||
make.height.equalTo(@80);
|
||||
}];
|
||||
|
||||
// 创建按钮
|
||||
NSMutableArray<UIButton *> *buttons = [NSMutableArray array];
|
||||
for (NSInteger i = 0; i < buttonConfigs.count; i++) {
|
||||
NSDictionary *config = buttonConfigs[i];
|
||||
UIButton *button = [self createHeaderButtonWithConfig:config];
|
||||
[self.headerView addSubview:button];
|
||||
[buttons addObject:button];
|
||||
|
||||
[button mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.equalTo(self.headerView);
|
||||
make.height.equalTo(@60);
|
||||
|
||||
if (i == 0) {
|
||||
// 第一个按钮:左边距16,右边到中点偏左6(总间距12的一半)
|
||||
make.left.equalTo(self.headerView).offset(16);
|
||||
make.right.equalTo(self.headerView.mas_centerX).offset(-6);
|
||||
} else if (i == 1) {
|
||||
// 第二个按钮:左边从中点偏右6,右边距16
|
||||
make.left.equalTo(self.headerView.mas_centerX).offset(6);
|
||||
make.right.equalTo(self.headerView).offset(-16);
|
||||
}
|
||||
}];
|
||||
}
|
||||
self.headerButtons = [buttons copy];
|
||||
}
|
||||
|
||||
- (void)setupCollectionView {
|
||||
// 创建 UICollectionViewFlowLayout
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
||||
layout.minimumInteritemSpacing = 12;
|
||||
layout.minimumLineSpacing = 16;
|
||||
layout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16);
|
||||
|
||||
// 创建 CollectionView
|
||||
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
self.collectionView.backgroundColor = [UIColor systemBackgroundColor];
|
||||
self.collectionView.delegate = self;
|
||||
self.collectionView.dataSource = self;
|
||||
self.collectionView.alwaysBounceVertical = YES;
|
||||
|
||||
// 注册自定义 Cell
|
||||
[self.collectionView registerClass:[AVLiveStreamCell class] forCellWithReuseIdentifier:kLiveStreamCellIdentifier];
|
||||
|
||||
[self.view addSubview:self.collectionView];
|
||||
|
||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.headerView.mas_bottom);
|
||||
make.left.right.bottom.equalTo(self.view);
|
||||
}];
|
||||
|
||||
// 添加下拉刷新
|
||||
self.refreshControl = [[UIRefreshControl alloc] init];
|
||||
[self.refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
|
||||
self.collectionView.refreshControl = self.refreshControl;
|
||||
}
|
||||
|
||||
- (UIButton *)createHeaderButtonWithConfig:(NSDictionary *)config {
|
||||
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
button.backgroundColor = [UIColor systemBlueColor];
|
||||
button.layer.cornerRadius = 10;
|
||||
button.clipsToBounds = YES;
|
||||
|
||||
// Create icon and title
|
||||
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:config[@"icon"]]];
|
||||
iconView.tintColor = [UIColor whiteColor];
|
||||
iconView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
|
||||
UILabel *titleLabel = [[UILabel alloc] init];
|
||||
titleLabel.text = config[@"title"];
|
||||
titleLabel.textColor = [UIColor whiteColor];
|
||||
titleLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightSemibold];
|
||||
titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
|
||||
[button addSubview:iconView];
|
||||
[button addSubview:titleLabel];
|
||||
|
||||
[iconView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.equalTo(button);
|
||||
make.centerY.equalTo(button).offset(-10);
|
||||
make.width.height.equalTo(@28);
|
||||
}];
|
||||
|
||||
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.equalTo(button);
|
||||
make.top.equalTo(iconView.mas_bottom).offset(4);
|
||||
make.left.greaterThanOrEqualTo(button).offset(8);
|
||||
make.right.lessThanOrEqualTo(button).offset(-8);
|
||||
}];
|
||||
|
||||
SEL action = NSSelectorFromString(config[@"action"]);
|
||||
[button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
#pragma mark - Network Request
|
||||
|
||||
- (void)fetchLiveStreams {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
[self.sessionManager GET:kLiveListAPIURL parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary *responseObject) {
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
if (!strongSelf) return;
|
||||
NSLog(@"%@",responseObject);
|
||||
[strongSelf.refreshControl endRefreshing];
|
||||
// 解析数据
|
||||
strongSelf.liveStreams = [NSArray yy_modelArrayWithClass:AVLiveStreamModel.class json:responseObject[@"list"]];
|
||||
|
||||
NSLog(@"✅ 成功获取 %ld 个直播流", (long)strongSelf.liveStreams.count);
|
||||
|
||||
// 刷新 UI
|
||||
[strongSelf.collectionView reloadData];
|
||||
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
if (!strongSelf) return;
|
||||
|
||||
[strongSelf.refreshControl endRefreshing];
|
||||
|
||||
NSLog(@"❌ 网络请求失败: %@", error.localizedDescription);
|
||||
|
||||
// 显示错误提示
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"加载失败"
|
||||
message:[NSString stringWithFormat:@"无法获取直播列表: %@", error.localizedDescription]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]];
|
||||
[strongSelf presentViewController:alert animated:YES completion:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)handleRefresh:(UIRefreshControl *)refreshControl {
|
||||
[self fetchLiveStreams];
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.liveStreams.count;
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
AVLiveStreamCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kLiveStreamCellIdentifier forIndexPath:indexPath];
|
||||
|
||||
AVLiveStreamModel *model = self.liveStreams[indexPath.item];
|
||||
|
||||
// 配置 Cell
|
||||
[cell configureWithModel:model];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDelegateFlowLayout
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)layout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// 每行显示 2 个,间距 12pt,左右边距各 16pt
|
||||
CGFloat totalHorizontalPadding = 16 * 2 + 12; // left + right + middle spacing
|
||||
CGFloat availableWidth = collectionView.bounds.size.width - totalHorizontalPadding;
|
||||
CGFloat itemWidth = availableWidth / 2.0;
|
||||
|
||||
// 缩略图宽高比 3:4
|
||||
CGFloat thumbnailHeight = itemWidth * (4.0 / 3.0);
|
||||
|
||||
// 计算总高度:
|
||||
// thumbnailHeight + 8 (spacing) + 17 (nameLabel) + 4 (spacing) + 16 (infoContainer) + 8 (bottom padding)
|
||||
CGFloat itemHeight = thumbnailHeight + 8 + 17 + 4 + 16 + 8;
|
||||
|
||||
return CGSizeMake(itemWidth, itemHeight);
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDelegate
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
|
||||
|
||||
AVLiveStreamModel *model = self.liveStreams[indexPath.item];
|
||||
|
||||
NSLog(@"🎬 点击播放 - stream: %@, protocol: %@", model.displayName, model.play_protocol);
|
||||
|
||||
// 直接使用模型跳转到播放器
|
||||
SCLiveVideoPlayerViewController *vc = [[SCLiveVideoPlayerViewController alloc] initWithLiveStream:model];
|
||||
vc.hidesBottomBarWhenPushed = YES;
|
||||
vc.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark - Button Actions
|
||||
|
||||
- (void)livePushTapped {
|
||||
// 创建 action sheet 让用户选择推流协议
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"开始直播"
|
||||
message:@"请选择推流协议"
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
// RTC 协议
|
||||
UIAlertAction *rtcAction = [UIAlertAction actionWithTitle:@"RTC 协议"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * _Nonnull action) {
|
||||
[self startLivePushWithProtocol:AVStreamProtocolRTC];
|
||||
}];
|
||||
[alert addAction:rtcAction];
|
||||
|
||||
// RTMP 协议
|
||||
UIAlertAction *rtmpAction = [UIAlertAction actionWithTitle:@"RTMP 协议"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * _Nonnull action) {
|
||||
[self startLivePushWithProtocol:AVStreamProtocolRTMP];
|
||||
}];
|
||||
[alert addAction:rtmpAction];
|
||||
|
||||
// 取消按钮
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil];
|
||||
[alert addAction:cancelAction];
|
||||
|
||||
// 在 iPad 上需要设置 popoverPresentationController
|
||||
if (alert.popoverPresentationController) {
|
||||
alert.popoverPresentationController.sourceView = self.view;
|
||||
alert.popoverPresentationController.sourceRect = CGRectMake(self.view.bounds.size.width / 2.0,
|
||||
self.view.bounds.size.height / 2.0,
|
||||
1.0, 1.0);
|
||||
alert.popoverPresentationController.permittedArrowDirections = 0;
|
||||
}
|
||||
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)startLivePushWithProtocol:(AVStreamProtocol)protocol {
|
||||
SCLivePusherViewController *vc = [[SCLivePusherViewController alloc] init];
|
||||
vc.videoConfig = [[[AVConfigManager sharedManager] globalConfig] copy];
|
||||
|
||||
// 默认使用竖屏(用户可以在直播页面通过旋转按钮切换)
|
||||
vc.videoConfig.outputImageOrientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
// 设置推流协议
|
||||
vc.protocol = protocol;
|
||||
|
||||
// 隐藏底部 TabBar
|
||||
vc.hidesBottomBarWhenPushed = YES;
|
||||
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
|
||||
NSLog(@"开始直播推流,协议: %@", AVStreamProtocolString(protocol));
|
||||
}
|
||||
|
||||
- (void)livePullTapped {
|
||||
// 弹出配置界面,让用户输入流信息
|
||||
SCPlayerConfigView *configView = [[SCPlayerConfigView alloc] init];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[configView showInViewController:self callback:^(SCPlayerConfig *config) {
|
||||
// 根据配置创建 AVLiveStreamModel
|
||||
AVLiveStreamModel *liveStream = [[AVLiveStreamModel alloc] init];
|
||||
liveStream.vhost = V_HOST;
|
||||
liveStream.app = APP_ID;
|
||||
liveStream.stream = config.streamId;
|
||||
liveStream.preview_image = @"";
|
||||
liveStream.duration = 0;
|
||||
liveStream.startTime = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
// 根据协议类型设置 playProtocol
|
||||
switch (config.protocol) {
|
||||
case SellyLiveMode_RTMP:
|
||||
liveStream.play_protocol = @"rtmp";
|
||||
break;
|
||||
case SellyLiveMode_RTC:
|
||||
liveStream.play_protocol = @"rtc";
|
||||
break;
|
||||
default:
|
||||
liveStream.play_protocol = @"rtmp";
|
||||
break;
|
||||
}
|
||||
|
||||
//这里仅做示例,实际上判断是直播还是点播
|
||||
if ([liveStream.stream.lowercaseString hasSuffix:@".mp4"]) {
|
||||
// 跳转到点播播放器
|
||||
SCVodVideoPlayerViewController *vc = [[SCVodVideoPlayerViewController alloc] initWithLiveStream:liveStream];
|
||||
vc.hidesBottomBarWhenPushed = YES;
|
||||
vc.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
[weakSelf.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
else {
|
||||
// 跳转到直播播放器
|
||||
SCLiveVideoPlayerViewController *vc = [[SCLiveVideoPlayerViewController alloc] initWithLiveStream:liveStream];
|
||||
vc.hidesBottomBarWhenPushed = YES;
|
||||
vc.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
[weakSelf.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Orientation Support (强制只支持竖屏)
|
||||
|
||||
- (BOOL)shouldAutorotate {
|
||||
return YES; // 允许旋转,但只支持竖屏
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
return UIInterfaceOrientationPortrait;
|
||||
}
|
||||
|
||||
@end
|
||||
19
Example/SellyCloudSDK/Controllers/Home/AVLiveStreamCell.h
Normal file
19
Example/SellyCloudSDK/Controllers/Home/AVLiveStreamCell.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// AVLiveStreamCell.h
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class AVLiveStreamModel;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AVLiveStreamCell : UICollectionViewCell
|
||||
|
||||
/// 配置 Cell 显示内容
|
||||
- (void)configureWithModel:(AVLiveStreamModel *)model;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
182
Example/SellyCloudSDK/Controllers/Home/AVLiveStreamCell.m
Normal file
182
Example/SellyCloudSDK/Controllers/Home/AVLiveStreamCell.m
Normal file
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// AVLiveStreamCell.m
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import "AVLiveStreamCell.h"
|
||||
#import "AVLiveStreamModel.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import <SDWebImage/SDWebImage.h>
|
||||
|
||||
@interface AVLiveStreamCell ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *thumbnailView;
|
||||
@property (nonatomic, strong) UIView *overlayView;
|
||||
@property (nonatomic, strong) UIImageView *playIcon;
|
||||
@property (nonatomic, strong) UILabel *durationLabel;
|
||||
@property (nonatomic, strong) UILabel *nameLabel;
|
||||
@property (nonatomic, strong) UILabel *liveLabel;
|
||||
@property (nonatomic, strong) UILabel *protocolLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AVLiveStreamCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self setupUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupUI {
|
||||
// 配置 Cell 背景
|
||||
self.contentView.backgroundColor = [UIColor secondarySystemBackgroundColor];
|
||||
self.contentView.layer.cornerRadius = 8;
|
||||
self.contentView.clipsToBounds = YES;
|
||||
|
||||
// 创建缩略图
|
||||
_thumbnailView = [[UIImageView alloc] init];
|
||||
_thumbnailView.backgroundColor = [UIColor systemGrayColor];
|
||||
_thumbnailView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_thumbnailView.clipsToBounds = YES;
|
||||
[self.contentView addSubview:_thumbnailView];
|
||||
|
||||
// 半透明遮罩层
|
||||
_overlayView = [[UIView alloc] init];
|
||||
_overlayView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.2];
|
||||
[_thumbnailView addSubview:_overlayView];
|
||||
|
||||
// 播放图标
|
||||
_playIcon = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"play.circle.fill"]];
|
||||
_playIcon.tintColor = [UIColor whiteColor];
|
||||
_playIcon.contentMode = UIViewContentModeScaleAspectFit;
|
||||
_playIcon.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||
_playIcon.layer.shadowOffset = CGSizeMake(0, 2);
|
||||
_playIcon.layer.shadowOpacity = 0.3;
|
||||
_playIcon.layer.shadowRadius = 4;
|
||||
[_thumbnailView addSubview:_playIcon];
|
||||
|
||||
// 直播时长标签
|
||||
_durationLabel = [[UILabel alloc] init];
|
||||
_durationLabel.font = [UIFont systemFontOfSize:12 weight:UIFontWeightMedium];
|
||||
_durationLabel.textColor = [UIColor whiteColor];
|
||||
_durationLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
|
||||
_durationLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_durationLabel.layer.cornerRadius = 4;
|
||||
_durationLabel.clipsToBounds = YES;
|
||||
[_thumbnailView addSubview:_durationLabel];
|
||||
|
||||
// 流名称标签
|
||||
_nameLabel = [[UILabel alloc] init];
|
||||
_nameLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightSemibold];
|
||||
_nameLabel.textColor = [UIColor labelColor];
|
||||
_nameLabel.numberOfLines = 1;
|
||||
[self.contentView addSubview:_nameLabel];
|
||||
|
||||
// 底部信息容器
|
||||
UIView *infoContainerView = [[UIView alloc] init];
|
||||
[self.contentView addSubview:infoContainerView];
|
||||
|
||||
// 直播状态标签
|
||||
_liveLabel = [[UILabel alloc] init];
|
||||
_liveLabel.text = @"🔴 直播中";
|
||||
_liveLabel.font = [UIFont systemFontOfSize:11 weight:UIFontWeightMedium];
|
||||
_liveLabel.textColor = [UIColor systemRedColor];
|
||||
[infoContainerView addSubview:_liveLabel];
|
||||
|
||||
// 协议标签
|
||||
_protocolLabel = [[UILabel alloc] init];
|
||||
_protocolLabel.font = [UIFont systemFontOfSize:10 weight:UIFontWeightMedium];
|
||||
_protocolLabel.textColor = [UIColor whiteColor];
|
||||
_protocolLabel.backgroundColor = [UIColor systemBlueColor];
|
||||
_protocolLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_protocolLabel.layer.cornerRadius = 3;
|
||||
_protocolLabel.clipsToBounds = YES;
|
||||
[infoContainerView addSubview:_protocolLabel];
|
||||
|
||||
// 布局
|
||||
[_thumbnailView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.left.right.equalTo(self.contentView);
|
||||
// 使用较低优先级的宽高比约束 3:4,允许它在必要时被压缩
|
||||
make.height.equalTo(_thumbnailView.mas_width).multipliedBy(4.0 / 3.0).priority(750);
|
||||
}];
|
||||
|
||||
[_overlayView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(_thumbnailView);
|
||||
}];
|
||||
|
||||
[_playIcon mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.equalTo(_thumbnailView);
|
||||
make.width.height.equalTo(@50);
|
||||
}];
|
||||
|
||||
[_durationLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.equalTo(_thumbnailView).offset(-8);
|
||||
make.right.equalTo(_thumbnailView).offset(-8);
|
||||
make.height.equalTo(@20);
|
||||
make.width.greaterThanOrEqualTo(@50);
|
||||
}];
|
||||
|
||||
[_nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(_thumbnailView.mas_bottom).offset(8);
|
||||
make.left.equalTo(self.contentView).offset(8);
|
||||
make.right.equalTo(self.contentView).offset(-8);
|
||||
}];
|
||||
|
||||
[infoContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(_nameLabel.mas_bottom).offset(4);
|
||||
make.left.equalTo(self.contentView).offset(8);
|
||||
make.right.lessThanOrEqualTo(self.contentView).offset(-8);
|
||||
make.bottom.lessThanOrEqualTo(self.contentView).offset(-8).priority(750);
|
||||
// 移除 height 的硬性约束,让它根据内容自适应
|
||||
}];
|
||||
|
||||
[_liveLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.top.bottom.equalTo(infoContainerView);
|
||||
}];
|
||||
|
||||
[_protocolLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(_liveLabel.mas_right).offset(8);
|
||||
make.centerY.equalTo(_liveLabel);
|
||||
make.height.equalTo(@16);
|
||||
make.width.greaterThanOrEqualTo(@40);
|
||||
make.right.lessThanOrEqualTo(infoContainerView);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)configureWithModel:(AVLiveStreamModel *)model {
|
||||
// 设置流名称
|
||||
_nameLabel.text = model.displayName;
|
||||
|
||||
// 设置时长
|
||||
_durationLabel.text = model.durationString;
|
||||
|
||||
// 设置协议标签
|
||||
_protocolLabel.text = model.play_protocol.uppercaseString;
|
||||
|
||||
// 使用 SDWebImage 加载预览图
|
||||
if (model.preview_image.length > 0) {
|
||||
NSURL *imageURL = [NSURL URLWithString:model.preview_image];
|
||||
|
||||
[_thumbnailView sd_setImageWithURL:imageURL];
|
||||
} else {
|
||||
// 没有预览图,清空图片
|
||||
_thumbnailView.image = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)prepareForReuse {
|
||||
[super prepareForReuse];
|
||||
|
||||
// 取消之前的图片加载任务
|
||||
[_thumbnailView sd_cancelCurrentImageLoad];
|
||||
|
||||
// 清空数据,防止复用时显示错误内容
|
||||
_thumbnailView.image = nil;
|
||||
_nameLabel.text = @"";
|
||||
_durationLabel.text = @"";
|
||||
_protocolLabel.text = @"";
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// AVNavigationController.h
|
||||
// AVDemo
|
||||
//
|
||||
// Created on 12/17/25.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 自定义导航控制器,用于转发屏幕方向控制权给顶层视图控制器
|
||||
@interface AVNavigationController : UINavigationController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// AVNavigationController.m
|
||||
// AVDemo
|
||||
//
|
||||
// Created on 12/17/25.
|
||||
//
|
||||
|
||||
#import "AVNavigationController.h"
|
||||
|
||||
@implementation AVNavigationController
|
||||
|
||||
#pragma mark - 屏幕方向控制
|
||||
|
||||
/// 是否支持自动旋转
|
||||
- (BOOL)shouldAutorotate {
|
||||
// 转发给顶层视图控制器
|
||||
return self.topViewController.shouldAutorotate;
|
||||
}
|
||||
|
||||
/// 支持的屏幕方向
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
// 转发给顶层视图控制器
|
||||
return self.topViewController.supportedInterfaceOrientations;
|
||||
}
|
||||
|
||||
/// 优先的屏幕方向
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
// 转发给顶层视图控制器
|
||||
return self.topViewController.preferredInterfaceOrientationForPresentation;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// AVSettingsViewController.h
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AVSettingsViewController : UIViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,282 @@
|
||||
//
|
||||
// AVSettingsViewController.m
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import "AVSettingsViewController.h"
|
||||
#import "AVConfigManager.h"
|
||||
#import "AVConstants.h"
|
||||
#import "AVUserManager.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import "UIView+SellyCloud.h"
|
||||
|
||||
@interface AVSettingsViewController () <UITextFieldDelegate>
|
||||
@property (nonatomic, strong) UIScrollView *scrollView;
|
||||
@property (nonatomic, strong) UIView *contentView;
|
||||
|
||||
@property (nonatomic, strong) UITextField *nicknameField;
|
||||
@property (nonatomic, strong) UISegmentedControl *resolutionSegment;
|
||||
@property (nonatomic, strong) UITextField *fpsField;
|
||||
@property (nonatomic, strong) UITextField *maxBitrateField;
|
||||
@property (nonatomic, strong) UITextField *minBitrateField;
|
||||
@end
|
||||
|
||||
@implementation AVSettingsViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.view.backgroundColor = [UIColor systemBackgroundColor];
|
||||
self.title = @"设置";
|
||||
|
||||
// 添加右上角提交日志按钮 - 延迟设置以避免约束冲突
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIBarButtonItem *uploadLogButton = [[UIBarButtonItem alloc] initWithTitle:@"提交日志"
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:self
|
||||
action:@selector(uploadLogButtonTapped)];
|
||||
self.navigationItem.rightBarButtonItem = uploadLogButton;
|
||||
});
|
||||
|
||||
[self setupUI];
|
||||
[self loadConfig];
|
||||
}
|
||||
|
||||
- (void)setupUI {
|
||||
_scrollView = [[UIScrollView alloc] init];
|
||||
[self.view addSubview:_scrollView];
|
||||
|
||||
_contentView = [[UIView alloc] init];
|
||||
[_scrollView addSubview:_contentView];
|
||||
|
||||
[_scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.view.mas_safeAreaLayoutGuideTop);
|
||||
make.left.right.bottom.equalTo(self.view);
|
||||
}];
|
||||
|
||||
[_contentView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(_scrollView);
|
||||
make.width.equalTo(_scrollView);
|
||||
}];
|
||||
|
||||
CGFloat topOffset = 20;
|
||||
CGFloat spacing = 30;
|
||||
|
||||
// Nickname
|
||||
topOffset = [self addLabel:@"用户昵称" atOffset:topOffset];
|
||||
_nicknameField = [self addTextField:@"请输入昵称" atOffset:topOffset];
|
||||
topOffset += 40 + spacing;
|
||||
|
||||
// Resolution
|
||||
topOffset = [self addLabel:@"分辨率" atOffset:topOffset];
|
||||
_resolutionSegment = [[UISegmentedControl alloc] initWithItems:@[@"360p", @"480p", @"540p", @"720p"]];
|
||||
[_contentView addSubview:_resolutionSegment];
|
||||
|
||||
[_resolutionSegment mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(_contentView).offset(20);
|
||||
make.right.equalTo(_contentView).offset(-20);
|
||||
make.top.equalTo(_contentView).offset(topOffset);
|
||||
make.height.equalTo(@32);
|
||||
}];
|
||||
topOffset += 32 + spacing;
|
||||
|
||||
// FPS
|
||||
topOffset = [self addLabel:@"帧率 (FPS)" atOffset:topOffset];
|
||||
_fpsField = [self addTextField:@"例如: 30" atOffset:topOffset];
|
||||
_fpsField.keyboardType = UIKeyboardTypeNumberPad;
|
||||
topOffset += 40 + spacing;
|
||||
|
||||
// Max bitrate
|
||||
topOffset = [self addLabel:@"最大码率 (kbps)" atOffset:topOffset];
|
||||
_maxBitrateField = [self addTextField:@"例如: 2000" atOffset:topOffset];
|
||||
_maxBitrateField.keyboardType = UIKeyboardTypeNumberPad;
|
||||
topOffset += 40 + spacing;
|
||||
|
||||
// Min bitrate
|
||||
topOffset = [self addLabel:@"最小码率 (kbps)" atOffset:topOffset];
|
||||
_minBitrateField = [self addTextField:@"例如: 500" atOffset:topOffset];
|
||||
_minBitrateField.keyboardType = UIKeyboardTypeNumberPad;
|
||||
topOffset += 40 + spacing;
|
||||
|
||||
// Save button
|
||||
UIButton *saveButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
[saveButton setTitle:@"保存设置" forState:UIControlStateNormal];
|
||||
saveButton.backgroundColor = [UIColor systemBlueColor];
|
||||
[saveButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
saveButton.titleLabel.font = [UIFont systemFontOfSize:17 weight:UIFontWeightSemibold];
|
||||
saveButton.layer.cornerRadius = 10;
|
||||
[saveButton addTarget:self action:@selector(saveConfig) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_contentView addSubview:saveButton];
|
||||
|
||||
[saveButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(_contentView).offset(20);
|
||||
make.right.equalTo(_contentView).offset(-20);
|
||||
make.top.equalTo(_contentView).offset(topOffset);
|
||||
make.height.equalTo(@50);
|
||||
}];
|
||||
topOffset += 50 + 20;
|
||||
|
||||
// Logout button
|
||||
UIButton *logoutButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
[logoutButton setTitle:@"退出登录" forState:UIControlStateNormal];
|
||||
logoutButton.backgroundColor = [UIColor systemRedColor];
|
||||
[logoutButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
logoutButton.titleLabel.font = [UIFont systemFontOfSize:17 weight:UIFontWeightSemibold];
|
||||
logoutButton.layer.cornerRadius = 10;
|
||||
[logoutButton addTarget:self action:@selector(logoutButtonTapped) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_contentView addSubview:logoutButton];
|
||||
|
||||
[logoutButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(_contentView).offset(20);
|
||||
make.right.equalTo(_contentView).offset(-20);
|
||||
make.top.equalTo(_contentView).offset(topOffset);
|
||||
make.height.equalTo(@50);
|
||||
}];
|
||||
topOffset += 50 + 20;
|
||||
|
||||
// 设置 contentView 的高度
|
||||
[_contentView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.equalTo(@(topOffset));
|
||||
}];
|
||||
|
||||
// Dismiss keyboard on tap
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
|
||||
[self.view addGestureRecognizer:tap];
|
||||
}
|
||||
|
||||
- (CGFloat)addLabel:(NSString *)text atOffset:(CGFloat)offset {
|
||||
UILabel *label = [[UILabel alloc] init];
|
||||
label.text = text;
|
||||
label.font = [UIFont systemFontOfSize:15 weight:UIFontWeightMedium];
|
||||
label.textColor = [UIColor labelColor];
|
||||
[_contentView addSubview:label];
|
||||
|
||||
[label mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(_contentView).offset(20);
|
||||
make.top.equalTo(_contentView).offset(offset);
|
||||
}];
|
||||
|
||||
return offset + 25;
|
||||
}
|
||||
|
||||
- (UITextField *)addTextField:(NSString *)placeholder atOffset:(CGFloat)offset {
|
||||
UITextField *textField = [[UITextField alloc] init];
|
||||
textField.placeholder = placeholder;
|
||||
textField.borderStyle = UITextBorderStyleRoundedRect;
|
||||
textField.delegate = self;
|
||||
[_contentView addSubview:textField];
|
||||
|
||||
[textField mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(_contentView).offset(20);
|
||||
make.right.equalTo(_contentView).offset(-20);
|
||||
make.top.equalTo(_contentView).offset(offset);
|
||||
make.height.equalTo(@40);
|
||||
}];
|
||||
|
||||
return textField;
|
||||
}
|
||||
|
||||
- (void)loadConfig {
|
||||
AVVideoConfiguration *config = [AVConfigManager sharedManager].globalConfig;
|
||||
|
||||
_nicknameField.text = config.nickname;
|
||||
_resolutionSegment.selectedSegmentIndex = [config currentResolution];
|
||||
_fpsField.text = [NSString stringWithFormat:@"%ld", (long)config.videoFrameRate];
|
||||
_maxBitrateField.text = [NSString stringWithFormat:@"%ld", (long)(config.videoBitRate / 1000)];
|
||||
_minBitrateField.text = [NSString stringWithFormat:@"%ld", (long)(config.videoMinBitRate / 1000)];
|
||||
}
|
||||
|
||||
- (void)saveConfig {
|
||||
AVVideoConfiguration *config = [AVConfigManager sharedManager].globalConfig;
|
||||
|
||||
config.nickname = _nicknameField.text.length > 0 ? _nicknameField.text : [AVConfigManager generateRandomNickname];
|
||||
[config setResolution:_resolutionSegment.selectedSegmentIndex];
|
||||
|
||||
NSInteger fps = [_fpsField.text integerValue] > 0 ? [_fpsField.text integerValue] : 30;
|
||||
config.videoFrameRate = fps;
|
||||
config.videoMaxKeyframeInterval = fps * 2;
|
||||
|
||||
NSInteger maxBitrate = [_maxBitrateField.text integerValue] > 0 ? [_maxBitrateField.text integerValue] : 2000;
|
||||
config.videoBitRate = maxBitrate * 1000; // Convert kbps to bps
|
||||
|
||||
NSInteger minBitrate = [_minBitrateField.text integerValue] > 0 ? [_minBitrateField.text integerValue] : 500;
|
||||
config.videoMinBitRate = minBitrate * 1000; // Convert kbps to bps
|
||||
|
||||
[[AVConfigManager sharedManager] saveConfig];
|
||||
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"成功" message:@"设置已保存" preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)logoutButtonTapped {
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"确认退出"
|
||||
message:@"确定要退出登录吗?"
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil];
|
||||
[alert addAction:cancelAction];
|
||||
|
||||
UIAlertAction *logoutAction = [UIAlertAction actionWithTitle:@"退出"
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction * _Nonnull action) {
|
||||
// 执行登出
|
||||
[[AVUserManager sharedManager] logout];
|
||||
|
||||
// 返回到登录页面
|
||||
// 通过 TabBarController 触发登录检查
|
||||
if ([self.tabBarController respondsToSelector:@selector(checkLoginStatus)]) {
|
||||
[self.tabBarController performSelector:@selector(checkLoginStatus)];
|
||||
}
|
||||
|
||||
NSLog(@"✅ 已退出登录");
|
||||
}];
|
||||
[alert addAction:logoutAction];
|
||||
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)uploadLogButtonTapped {
|
||||
// 调用 SellyCloudManager 的 uploadLog 方法
|
||||
[SellyCloudManager uploadLog:^(NSString * _Nullable url, NSError * _Nullable error) {
|
||||
UIAlertController *resultAlert;
|
||||
if (error) {
|
||||
// 上传失败
|
||||
resultAlert = [UIAlertController alertControllerWithTitle:@"上传失败"
|
||||
message:[NSString stringWithFormat:@"日志上传失败: %@", error.localizedDescription]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[resultAlert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]];
|
||||
} else {
|
||||
// 上传成功
|
||||
NSString *message = url ? [NSString stringWithFormat:@"日志已成功上传\n地址: %@", url] : @"日志已成功上传";
|
||||
resultAlert = [UIAlertController alertControllerWithTitle:@"上传成功"
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
NSLog(@"###日志url == %@",url);
|
||||
|
||||
// 点击确定后将 URL 复制到粘贴板
|
||||
UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"确定"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * _Nonnull action) {
|
||||
if (url.length > 0) {
|
||||
UIPasteboard.generalPasteboard.string = url;
|
||||
[self.view showToast:@"日志 URL 已复制到粘贴板"];
|
||||
}
|
||||
}];
|
||||
[resultAlert addAction:confirmAction];
|
||||
}
|
||||
[self presentViewController:resultAlert animated:YES completion:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard {
|
||||
[self.view endEditing:YES];
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
[textField resignFirstResponder];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// UINavigationController+Orientation.h
|
||||
// AVDemo
|
||||
//
|
||||
// 让导航控制器将方向决策交给顶层 ViewController
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UINavigationController (Orientation)
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// UINavigationController+Orientation.m
|
||||
// AVDemo
|
||||
//
|
||||
// 让导航控制器将方向决策交给顶层 ViewController
|
||||
//
|
||||
|
||||
#import "UINavigationController+Orientation.h"
|
||||
|
||||
@implementation UINavigationController (Orientation)
|
||||
|
||||
- (BOOL)shouldAutorotate {
|
||||
// 将决策权交给顶层 ViewController
|
||||
return [self.topViewController shouldAutorotate];
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
// 将决策权交给顶层 ViewController
|
||||
return [self.topViewController supportedInterfaceOrientations];
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
// 将决策权交给顶层 ViewController
|
||||
return [self.topViewController preferredInterfaceOrientationForPresentation];
|
||||
}
|
||||
|
||||
@end
|
||||
17
Example/SellyCloudSDK/CrashHandler.h
Normal file
17
Example/SellyCloudSDK/CrashHandler.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// CrashHandler.h
|
||||
// SellyCloudSDK_Example
|
||||
//
|
||||
// Created by Caleb on 24/10/25.
|
||||
// Copyright © 2025 Caleb. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CrashHandler : NSObject
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
132
Example/SellyCloudSDK/CrashHandler.m
Normal file
132
Example/SellyCloudSDK/CrashHandler.m
Normal file
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// CrashHandler.m
|
||||
// SellyCloudSDK_Example
|
||||
//
|
||||
// Created by Caleb on 24/10/25.
|
||||
// Copyright © 2025 Caleb. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CrashHandler.h"
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <execinfo.h>
|
||||
#include <signal.h>
|
||||
#import <CocoaLumberjack/CocoaLumberjack.h>
|
||||
|
||||
@interface CrashHandler ()
|
||||
|
||||
@end
|
||||
|
||||
void HandleException(NSException *exception);
|
||||
void SignalHandler(int signal);
|
||||
|
||||
@implementation CrashHandler
|
||||
|
||||
+ (void)load {
|
||||
[self installCrashHandler];
|
||||
}
|
||||
|
||||
+ (void)installCrashHandler {
|
||||
// 1. 捕获 Objective-C 异常
|
||||
NSSetUncaughtExceptionHandler(&HandleException);
|
||||
|
||||
// 2. 捕获 Unix 信号
|
||||
signal(SIGABRT, SignalHandler);
|
||||
signal(SIGILL, SignalHandler);
|
||||
signal(SIGSEGV, SignalHandler);
|
||||
signal(SIGFPE, SignalHandler);
|
||||
signal(SIGBUS, SignalHandler);
|
||||
signal(SIGPIPE, SignalHandler);
|
||||
}
|
||||
|
||||
+ (NSString *)crashLogPath {
|
||||
NSString *doc = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
|
||||
return [doc stringByAppendingPathComponent:@"crash.log"];
|
||||
}
|
||||
|
||||
+ (void)saveCrashToLocal:(NSString *)txt {
|
||||
// DDLogInfo(@"####crashed:");
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
BOOL isDir = NO;
|
||||
BOOL dataIsDir = NO;
|
||||
// fileExistsAtPath 判断一个文件或目录是否有效,isDirectory判断是否一个目录
|
||||
NSString* dirPath = [applicationDocumentsDirectory() stringByAppendingPathComponent:@"ErrorLog"];
|
||||
NSString* filePath = [dirPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.txt", CarshDate()]];
|
||||
BOOL existed = [fileManager fileExistsAtPath:dirPath isDirectory:&isDir];
|
||||
BOOL dataExisted = [fileManager fileExistsAtPath:filePath isDirectory:&dataIsDir];
|
||||
if (!(isDir == YES && existed == YES)) { //如果文件夹不存在
|
||||
[fileManager createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
}
|
||||
if (!(dataIsDir == YES && dataExisted == YES)) {
|
||||
[txt writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
// 沙盒地址
|
||||
NSString* applicationDocumentsDirectory(void)
|
||||
{
|
||||
return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
|
||||
}
|
||||
|
||||
NSString* CarshDate(void)
|
||||
{
|
||||
NSDateFormatter* formatter = [NSDateFormatter new];
|
||||
[formatter setDateFormat:@"yyyy-MM-dd_HHmmss"];
|
||||
|
||||
return [formatter stringFromDate:[NSDate date]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// 崩溃时的回调函数
|
||||
void HandleException(NSException* exception)
|
||||
{
|
||||
NSArray* arr = [exception callStackSymbols];
|
||||
// 崩溃的原因 可以有崩溃的原因(数组越界,字典nil,调用未知方法...) 崩溃的控制器以及方法
|
||||
NSString* reason = [exception reason];
|
||||
NSString* name = [exception name];
|
||||
NSDictionary* userInfo = [exception userInfo];
|
||||
NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary];
|
||||
// app名称
|
||||
NSString* app_Name = [infoDictionary objectForKey:@"CFBundleDisplayName"];
|
||||
// app版本
|
||||
NSString* app_Version = [infoDictionary objectForKey:@"CFBundleShortVersionString"];
|
||||
// app build版本
|
||||
NSString* app_build = [infoDictionary objectForKey:@"CFBundleVersion"];
|
||||
//手机型号
|
||||
NSString* phoneModel = [[UIDevice currentDevice] model];
|
||||
//手机系统版本
|
||||
NSString* phoneVersion = [[UIDevice currentDevice] systemVersion];
|
||||
|
||||
NSString* txt = [NSString stringWithFormat:@"========异常错误报告========\n\n"
|
||||
@"手机型号:%@ 版本:%@\n"
|
||||
@"App名称:%@ 版本:%@(%@)\n\n"
|
||||
@"name:%@\n"
|
||||
@"userInfo:%@\n\n"
|
||||
@"reason:\n%@\n\n"
|
||||
@"callStackSymbols:\n%@",
|
||||
phoneModel, phoneVersion,
|
||||
app_Name, app_Version, app_build,
|
||||
name, userInfo, reason,
|
||||
[arr componentsJoinedByString:@"\n"]];
|
||||
|
||||
[CrashHandler saveCrashToLocal:txt];
|
||||
}
|
||||
|
||||
|
||||
void SignalHandler(int signal) {
|
||||
// 获取调用栈
|
||||
void *callstack[128];
|
||||
int frames = backtrace(callstack, 128);
|
||||
char **strs = backtrace_symbols(callstack, frames);
|
||||
|
||||
NSMutableString *stackStr = [NSMutableString string];
|
||||
for (int i = 0; i < frames; i++) {
|
||||
[stackStr appendFormat:@"%s\n", strs[i]];
|
||||
}
|
||||
|
||||
NSString *content = [NSString stringWithFormat:@"Signal %d was raised.\nStack:\n%@", signal, stackStr];
|
||||
NSString *path = [CrashHandler crashLogPath];
|
||||
[content writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||||
|
||||
free(strs);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "appicon.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 151 KiB |
68
Example/SellyCloudSDK/Live/AVVideoConfiguration.h
Normal file
68
Example/SellyCloudSDK/Live/AVVideoConfiguration.h
Normal file
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// AVVideoConfiguration.h
|
||||
// AVDemo
|
||||
//
|
||||
// 自定义视频配置类,继承自 SellyLiveVideoConfiguration
|
||||
// 添加业务相关的属性和方法
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SellyCloudSDK/SellyCloudManager.h"
|
||||
#import "AVConstants.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 自定义视频配置类
|
||||
/// @discussion 继承自 SellyLiveVideoConfiguration,添加了业务相关的属性
|
||||
@interface AVVideoConfiguration : SellyLiveVideoConfiguration
|
||||
|
||||
// ============ 业务属性 ============
|
||||
|
||||
/// 用户昵称
|
||||
@property (nonatomic, copy) NSString *nickname;
|
||||
|
||||
/// 流 ID
|
||||
@property (nonatomic, copy) NSString *streamId;
|
||||
|
||||
/// 视频编码器(H.264/H.265)
|
||||
@property (nonatomic, assign) AVVideoCodec codec;
|
||||
|
||||
// ============ 工厂方法 ============
|
||||
|
||||
/// 创建默认配置
|
||||
+ (instancetype)defaultConfiguration;
|
||||
|
||||
/// 创建指定分辨率的配置
|
||||
/// @param resolution 分辨率
|
||||
+ (instancetype)configurationWithResolution:(AVVideoResolution)resolution;
|
||||
|
||||
// ============ 便利方法 ============
|
||||
|
||||
/// 设置分辨率(采集和输出相同)
|
||||
/// @param resolution 分辨率
|
||||
- (void)setResolution:(AVVideoResolution)resolution;
|
||||
|
||||
/// 分别设置采集和输出分辨率(高级用法)
|
||||
/// @param captureResolution 采集分辨率
|
||||
/// @param outputResolution 输出分辨率
|
||||
- (void)setCaptureResolution:(AVVideoResolution)captureResolution
|
||||
outputResolution:(AVVideoResolution)outputResolution;
|
||||
|
||||
/// 获取当前输出分辨率
|
||||
- (AVVideoResolution)currentResolution;
|
||||
|
||||
/// 获取当前采集分辨率
|
||||
- (AVVideoResolution)currentCaptureResolution;
|
||||
|
||||
/// 获取当前输出分辨率
|
||||
- (AVVideoResolution)currentOutputResolution;
|
||||
|
||||
/// 获取最大码率(kbps)
|
||||
- (NSInteger)maxBitrateKbps;
|
||||
|
||||
/// 获取最小码率(kbps)
|
||||
- (NSInteger)minBitrateKbps;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
167
Example/SellyCloudSDK/Live/AVVideoConfiguration.m
Normal file
167
Example/SellyCloudSDK/Live/AVVideoConfiguration.m
Normal file
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// AVVideoConfiguration.m
|
||||
// AVDemo
|
||||
//
|
||||
|
||||
#import "AVVideoConfiguration.h"
|
||||
|
||||
@implementation AVVideoConfiguration
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
// 初始化默认值
|
||||
_nickname = @"";
|
||||
_streamId = @"";
|
||||
_codec = AVVideoCodeH264;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Factory Methods
|
||||
|
||||
+ (instancetype)defaultConfiguration {
|
||||
AVVideoConfiguration *config = [[AVVideoConfiguration alloc] init];
|
||||
|
||||
// 生成随机昵称
|
||||
NSInteger randomNum = arc4random_uniform(1000);
|
||||
config.nickname = [NSString stringWithFormat:@"test%03ld", (long)randomNum];
|
||||
|
||||
// 生成随机 streamId:stream + 3位随机数字
|
||||
NSInteger streamRandomNum = 100 + arc4random_uniform(900); // 100-999
|
||||
config.streamId = [NSString stringWithFormat:@"%ld", (long)streamRandomNum];
|
||||
|
||||
config.codec = AVVideoCodeH264;
|
||||
|
||||
// 设置默认分辨率为 720p
|
||||
[config setResolution:AVVideoResolution360p];
|
||||
|
||||
// 设置默认视频参数
|
||||
config.videoFrameRate = 20;
|
||||
config.videoMinFrameRate = 15;
|
||||
config.videoMaxKeyframeInterval = 60; // 2x fps
|
||||
|
||||
// 设置默认码率(kbps → bps)
|
||||
config.videoBitRate = 2000 * 1000; // 2000 kbps
|
||||
config.videoMinBitRate = 500 * 1000; // 500 kbps
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
+ (instancetype)configurationWithResolution:(AVVideoResolution)resolution {
|
||||
AVVideoConfiguration *config = [self defaultConfiguration];
|
||||
[config setResolution:resolution];
|
||||
return config;
|
||||
}
|
||||
|
||||
#pragma mark - Resolution Management
|
||||
|
||||
- (void)setResolution:(AVVideoResolution)resolution {
|
||||
// 默认:采集和输出使用相同分辨率
|
||||
[self setCaptureResolution:resolution outputResolution:resolution];
|
||||
}
|
||||
|
||||
- (void)setCaptureResolution:(AVVideoResolution)captureResolution
|
||||
outputResolution:(AVVideoResolution)outputResolution {
|
||||
// 设置输出分辨率(videoSize)
|
||||
CGSize outputSize = AVVideoResolutionSize(outputResolution);
|
||||
self.videoSize = outputSize;
|
||||
|
||||
// 根据输出分辨率自动调整码率
|
||||
[self adjustBitrateForResolution:outputResolution];
|
||||
}
|
||||
|
||||
- (void)adjustBitrateForResolution:(AVVideoResolution)resolution {
|
||||
NSUInteger maxBitrate, minBitrate;
|
||||
|
||||
switch (resolution) {
|
||||
case AVVideoResolution360p:
|
||||
maxBitrate = 600;
|
||||
minBitrate = 300;
|
||||
break;
|
||||
case AVVideoResolution480p:
|
||||
maxBitrate = 900;
|
||||
minBitrate = 400;
|
||||
break;
|
||||
case AVVideoResolution540p:
|
||||
maxBitrate = 1500;
|
||||
minBitrate = 500;
|
||||
break;
|
||||
case AVVideoResolution720p:
|
||||
maxBitrate = 2000;
|
||||
minBitrate = 800;
|
||||
break;
|
||||
}
|
||||
|
||||
self.videoBitRate = maxBitrate * 1000; // Convert kbps to bps
|
||||
self.videoMinBitRate = minBitrate * 1000; // Convert kbps to bps
|
||||
}
|
||||
|
||||
- (AVVideoResolution)currentResolution {
|
||||
// 返回输出分辨率
|
||||
return [self currentOutputResolution];
|
||||
}
|
||||
|
||||
- (AVVideoResolution)currentOutputResolution {
|
||||
// 根据 videoSize 返回输出分辨率
|
||||
CGSize size = self.videoSize;
|
||||
|
||||
// 处理横屏和竖屏(统一为横屏比较)
|
||||
CGFloat width = MAX(size.width, size.height);
|
||||
CGFloat height = MIN(size.width, size.height);
|
||||
|
||||
if (width == 640 && height == 360) {
|
||||
return AVVideoResolution360p;
|
||||
} else if (width == 854 && height == 480) {
|
||||
return AVVideoResolution480p;
|
||||
} else if (width == 960 && height == 540) {
|
||||
return AVVideoResolution540p;
|
||||
} else if (width == 1280 && height == 720) {
|
||||
return AVVideoResolution720p;
|
||||
}
|
||||
|
||||
// 默认返回 720p
|
||||
return AVVideoResolution720p;
|
||||
}
|
||||
|
||||
#pragma mark - Convenience Accessors
|
||||
|
||||
- (NSInteger)maxBitrateKbps {
|
||||
return self.videoBitRate / 1000;
|
||||
}
|
||||
|
||||
- (NSInteger)minBitrateKbps {
|
||||
return self.videoMinBitRate / 1000;
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
// 调用父类的 copy 方法
|
||||
AVVideoConfiguration *copy = [super copyWithZone:zone];
|
||||
|
||||
// 复制自己的属性
|
||||
copy.nickname = [self.nickname copy];
|
||||
copy.streamId = [self.streamId copy];
|
||||
copy.codec = self.codec;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableString *desc = @"".mutableCopy;
|
||||
[desc appendFormat:@"<AVVideoConfiguration: %p>\n", self];
|
||||
[desc appendFormat:@" nickname: %@\n", self.nickname];
|
||||
[desc appendFormat:@" streamId: %@\n", self.streamId];
|
||||
[desc appendFormat:@" codec: %@\n", AVVideoCodecString(self.codec)];
|
||||
[desc appendFormat:@" videoSize: %@\n", NSStringFromCGSize(self.videoSize)];
|
||||
[desc appendFormat:@" videoFrameRate: %lu\n", (unsigned long)self.videoFrameRate];
|
||||
[desc appendFormat:@" videoBitRate: %lu kbps\n", (unsigned long)(self.videoBitRate / 1000)];
|
||||
[desc appendFormat:@" videoMinBitRate: %lu kbps", (unsigned long)(self.videoMinBitRate / 1000)];
|
||||
return desc;
|
||||
}
|
||||
|
||||
@end
|
||||
31
Example/SellyCloudSDK/Live/Beauty/FUManager.h
Executable file
31
Example/SellyCloudSDK/Live/Beauty/FUManager.h
Executable file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// FUManager.h
|
||||
// FULiveDemo
|
||||
//
|
||||
// Created by 刘洋 on 2017/8/18.
|
||||
// Copyright © 2017年 刘洋. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <FURenderKit/FURenderKit.h>
|
||||
|
||||
@interface FUManager : NSObject
|
||||
|
||||
@property (nonatomic, assign, readonly) FUDevicePerformanceLevel devicePerformanceLevel;
|
||||
|
||||
+ (FUManager *)shareManager;
|
||||
|
||||
/// 销毁全部道具
|
||||
- (void)destoryItems;
|
||||
|
||||
/// 切换前后摄像头
|
||||
- (void)onCameraChange;
|
||||
|
||||
/// 更新美颜磨皮效果(根据人脸检测置信度设置不同磨皮效果)
|
||||
- (void)updateBeautyBlurEffect;
|
||||
|
||||
- (CVPixelBufferRef)renderItemsToPixelBuffer:(CVPixelBufferRef)buffer;
|
||||
|
||||
@end
|
||||
138
Example/SellyCloudSDK/Live/Beauty/FUManager.m
Executable file
138
Example/SellyCloudSDK/Live/Beauty/FUManager.m
Executable file
@@ -0,0 +1,138 @@
|
||||
//
|
||||
// FUManager.m
|
||||
// FULiveDemo
|
||||
//
|
||||
// Created by 刘洋 on 2017/8/18.
|
||||
// Copyright © 2017年 刘洋. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FUManager.h"
|
||||
#import "FUBeautyComponentManager.h"
|
||||
#import "authpack.h"
|
||||
#import <FURenderKit/FUGLDisplayView.h>
|
||||
|
||||
static FUManager *shareManager = NULL;
|
||||
|
||||
@interface FUManager ()
|
||||
|
||||
@property (nonatomic, assign) FUDevicePerformanceLevel devicePerformanceLevel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUManager
|
||||
|
||||
+ (FUManager *)shareManager
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
shareManager = [[FUManager alloc] init];
|
||||
});
|
||||
return shareManager;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
|
||||
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
|
||||
|
||||
NSString *controllerPath = [[NSBundle mainBundle] pathForResource:@"controller_cpp" ofType:@"bundle"];
|
||||
NSString *controllerConfigPath = [[NSBundle mainBundle] pathForResource:@"controller_config" ofType:@"bundle"];
|
||||
FUSetupConfig *setupConfig = [[FUSetupConfig alloc] init];
|
||||
setupConfig.authPack = FUAuthPackMake(g_auth_package, sizeof(g_auth_package));
|
||||
setupConfig.controllerPath = controllerPath;
|
||||
setupConfig.controllerConfigPath = controllerConfigPath;
|
||||
|
||||
// 初始化 FURenderKit
|
||||
[FURenderKit setupWithSetupConfig:setupConfig];
|
||||
|
||||
[FURenderKit setLogLevel:FU_LOG_LEVEL_INFO];
|
||||
|
||||
self.devicePerformanceLevel = [FURenderKit devicePerformanceLevel];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
// 加载人脸 AI 模型
|
||||
NSString *faceAIPath = [[NSBundle mainBundle] pathForResource:@"ai_face_processor" ofType:@"bundle"];
|
||||
[FUAIKit loadAIModeWithAIType:FUAITYPE_FACEPROCESSOR dataPath:faceAIPath];
|
||||
|
||||
// 加载身体 AI 模型,注意:高性能机型加载ai_human_processor_gpu.bundle
|
||||
NSString *humanBundleName = self.devicePerformanceLevel == FUDevicePerformanceLevelHigh ? @"ai_human_processor_gpu" : @"ai_human_processor";
|
||||
NSString *bodyAIPath = [[NSBundle mainBundle] pathForResource:humanBundleName ofType:@"bundle"];
|
||||
[FUAIKit loadAIModeWithAIType:FUAITYPE_HUMAN_PROCESSOR dataPath:bodyAIPath];
|
||||
|
||||
CFAbsoluteTime endTime = (CFAbsoluteTimeGetCurrent() - startTime);
|
||||
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:@"tongue" ofType:@"bundle"];
|
||||
[FUAIKit loadTongueMode:path];
|
||||
|
||||
//TODO: todo 是否需要用?????
|
||||
/* 设置嘴巴灵活度 默认= 0*/ //
|
||||
float flexible = 0.5;
|
||||
[FUAIKit setFaceTrackParam:@"mouth_expression_more_flexible" value:flexible];
|
||||
NSLog(@"---%lf",endTime);
|
||||
|
||||
// 设置人脸算法质量
|
||||
[FUAIKit shareKit].faceProcessorFaceLandmarkQuality = self.devicePerformanceLevel == FUDevicePerformanceLevelHigh ? FUFaceProcessorFaceLandmarkQualityHigh : FUFaceProcessorFaceLandmarkQualityMedium;
|
||||
|
||||
// 设置小脸检测是否打开
|
||||
[FUAIKit shareKit].faceProcessorDetectSmallFace = self.devicePerformanceLevel == FUDevicePerformanceLevelHigh;
|
||||
});
|
||||
[FURenderKit shareRenderKit].beauty = [self defaultBeauty];
|
||||
[FUBeautyComponentManager.sharedManager beautyStyleSetAllDefaultValues];
|
||||
[FUAIKit shareKit].maxTrackFaces = 4;
|
||||
|
||||
FUBeauty *beauty = [FURenderKit shareRenderKit].beauty;
|
||||
beauty.colorLevel = 1;
|
||||
beauty.redLevel = 1;
|
||||
beauty.cheekThinning = 1;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)destoryItems {
|
||||
[FURenderKit shareRenderKit].beauty = nil;
|
||||
[FURenderKit shareRenderKit].bodyBeauty = nil;
|
||||
[FURenderKit shareRenderKit].makeup = nil;
|
||||
[[FURenderKit shareRenderKit].stickerContainer removeAllSticks];
|
||||
}
|
||||
|
||||
|
||||
- (void)onCameraChange {
|
||||
[FUAIKit resetTrackedResult];
|
||||
}
|
||||
|
||||
- (FUBeauty *)defaultBeauty {
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:@"face_beautification" ofType:@"bundle"];
|
||||
FUBeauty *beauty = [[FUBeauty alloc] initWithPath:path name:@"FUBeauty"];
|
||||
beauty.colorLevel = 1;
|
||||
beauty.redLevel = 1;
|
||||
beauty.cheekThinning = 1;
|
||||
return beauty;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - VideoFilterDelegate
|
||||
|
||||
- (CVPixelBufferRef)renderItemsToPixelBuffer:(CVPixelBufferRef)frame {
|
||||
if (UIApplication.sharedApplication.applicationState == UIApplicationStateBackground) {
|
||||
return frame;
|
||||
} else {
|
||||
// 前台才调用 FURenderKit 渲染
|
||||
FURenderInput *input = [[FURenderInput alloc] init];
|
||||
input.pixelBuffer = frame;
|
||||
//默认图片内部的人脸始终是朝上,旋转屏幕也无需修改该属性。
|
||||
input.renderConfig.imageOrientation = FUImageOrientationUP;
|
||||
//开启重力感应,内部会自动计算正确方向,设置fuSetDefaultRotationMode,无须外面设置
|
||||
input.renderConfig.gravityEnable = YES;
|
||||
//如果来源相机捕获的图片一定要设置,否则将会导致内部检测异常
|
||||
input.renderConfig.isFromFrontCamera = YES;
|
||||
//该属性是指系统相机是否做了镜像: 一般情况前置摄像头出来的帧都是设置过镜像,所以默认需要设置下。如果相机属性未设置镜像,改属性不用设置。
|
||||
input.renderConfig.isFromMirroredCamera = YES;
|
||||
FURenderOutput *output = [[FURenderKit shareRenderKit] renderWithInput:input];
|
||||
return output.pixelBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
BIN
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/FURenderKit
Executable file
BIN
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/FURenderKit
Executable file
Binary file not shown.
1997
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/CNamaSDK.h
Executable file
1997
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/CNamaSDK.h
Executable file
File diff suppressed because it is too large
Load Diff
58
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUAIConfig.h
Executable file
58
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUAIConfig.h
Executable file
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// FUAIConfig.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/20.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUConfig.h"
|
||||
#import "FUStruct.h"
|
||||
|
||||
typedef enum : NSUInteger {
|
||||
FUBodyTrackModeHalf,
|
||||
FUBodyTrackModeFull,
|
||||
} FUBodyTrackMode;
|
||||
|
||||
typedef enum : NSUInteger {
|
||||
FUBodyTrackStatusNoBody,
|
||||
FUBodyTrackStatusHalfLessBody,
|
||||
FUBodyTrackStatusHalfBody,
|
||||
FUBodyTrackStatusHalfMoreBody,
|
||||
FUBodyTrackStatusFullBody
|
||||
} FUBodyTrackStatus;
|
||||
|
||||
@interface FUAIConfig : FUConfig
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAIConfig (AR)
|
||||
|
||||
@property (nonatomic, assign) BOOL ARModeEnable;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAIConfig (FaceTrack)
|
||||
|
||||
@property (nonatomic, assign) BOOL faceTrackEnable;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAIConfig (BodyTrack)
|
||||
|
||||
@property (nonatomic, assign) BOOL bodyTrackEnable;
|
||||
|
||||
@property (nonatomic, assign) FUBodyTrackMode bodyTrackMode;
|
||||
|
||||
@property (nonatomic, assign) BOOL handDetector;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAIConfig (Avatar)
|
||||
|
||||
@property (nonatomic, assign) FUPosition avatarTranslationScale;
|
||||
|
||||
/// 抖动参数设置
|
||||
- (void)setAvatarAnimFilter:(int)bufferFrames pos:(float)pos angle:(float)angle;
|
||||
|
||||
@end
|
||||
323
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUAIKit.h
Executable file
323
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUAIKit.h
Executable file
@@ -0,0 +1,323 @@
|
||||
//
|
||||
// FUAIKit.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by liuyang on 2021/3/2.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "CNamaSDK.h"
|
||||
#import "FURenderIO.h"
|
||||
|
||||
@class FUTrackFaceInput;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 人脸检测模式
|
||||
typedef enum : NSUInteger {
|
||||
FUFaceProcessorDetectModeImage,
|
||||
FUFaceProcessorDetectModeVideo,
|
||||
} FUFaceProcessorDetectMode;
|
||||
|
||||
/// 人体检测模式
|
||||
typedef enum : NSUInteger {
|
||||
FUHumanProcessorDetectModeImage,
|
||||
FUHumanProcessorDetectModeVideo
|
||||
} FUHumanProcessorDetectMode;
|
||||
|
||||
/// 人脸点位算法性能
|
||||
typedef enum : NSUInteger {
|
||||
FUFaceProcessorFaceLandmarkQualityLow,
|
||||
FUFaceProcessorFaceLandmarkQualityMedium,
|
||||
FUFaceProcessorFaceLandmarkQualityHigh
|
||||
} FUFaceProcessorFaceLandmarkQuality;
|
||||
|
||||
/// 人脸模型设置
|
||||
typedef enum : NSInteger {
|
||||
FUFaceModelConfigDefault = -1
|
||||
} FUFaceModelConfig;
|
||||
|
||||
/// 人脸算法设置
|
||||
typedef enum : NSUInteger {
|
||||
FUFaceAlgorithmConfigEnableAll = 0, // 打开全部效果
|
||||
FUFaceAlgorithmConfigDisableFaceOccu = 1 << 0, // 关闭全脸分割
|
||||
FUFaceAlgorithmConfigDisableSkinSeg = 1 << 1, // 关闭皮肤分割
|
||||
FUFaceAlgorithmConfigDisableDelSpot = 1 << 2, // 关闭祛斑痘
|
||||
FUFaceAlgorithmConfigDisableARMeshV2 = 1 << 3, // 关闭 ARMeshV2
|
||||
FUFaceAlgorithmConfigDisableRACE = 1 << 4, // 关闭人种分类
|
||||
FUFaceAlgorithmConfigDisableLANDMARK_HP_OCCU = 1 << 5, //关闭高质量遮挡
|
||||
|
||||
FUFaceAlgorithmConfigDisableFaceOccuAndSkinSeg = FUFaceAlgorithmConfigDisableFaceOccu | FUFaceAlgorithmConfigDisableSkinSeg,
|
||||
FUFaceAlgorithmConfigDisableFaceOccuAndDelSpot = FUFaceAlgorithmConfigDisableFaceOccu | FUFaceAlgorithmConfigDisableDelSpot,
|
||||
FUFaceAlgorithmConfigDisableSkinSegAndDelSpot = FUFaceAlgorithmConfigDisableSkinSeg | FUFaceAlgorithmConfigDisableDelSpot,
|
||||
FUFaceAlgorithmConfigDisableFaceOccuAndSkinSegAndDelSpot = FUFaceAlgorithmConfigDisableFaceOccu | FUFaceAlgorithmConfigDisableSkinSeg | FUFaceAlgorithmConfigDisableDelSpot,
|
||||
FUFaceAlgorithmConfigDisableAll = FUFaceAlgorithmConfigDisableFaceOccu | FUFaceAlgorithmConfigDisableSkinSeg | FUFaceAlgorithmConfigDisableDelSpot | FUFaceAlgorithmConfigDisableARMeshV2 | FUFaceAlgorithmConfigDisableRACE | FUFaceAlgorithmConfigDisableLANDMARK_HP_OCCU
|
||||
} FUFaceAlgorithmConfig;
|
||||
|
||||
/// 人体分割场景
|
||||
typedef enum : NSUInteger {
|
||||
FUHumanSegmentationSceneTypeMeeting = 0, // 视频会议
|
||||
FUHumanSegmentationSceneTypeCommon // 通用
|
||||
} FUHumanSegmentationSceneType;
|
||||
|
||||
/// 人体分割模式
|
||||
typedef enum : NSUInteger {
|
||||
FUHumanSegmentationModeCPUCommon = 0x00, // CPU通用模式
|
||||
FUHumanSegmentationModeGPUCommon = 0x01, // GPU通用模式
|
||||
FUHumanSegmentationModeGPUMeeting = 0x02 // GPU会议模式
|
||||
} FUHumanSegmentationMode;
|
||||
|
||||
/// 人体算法设置
|
||||
typedef enum : NSUInteger {
|
||||
FUHumanAlgorithmConfigEnableAll = 0, // 打开全部效果
|
||||
FUHumanAlgorithmConfigDisableSeg = 1 << 0, // 关闭人体分割
|
||||
} FUHumanAlgorithmConfig;
|
||||
|
||||
@interface FUAIKit : NSObject
|
||||
|
||||
@property (nonatomic, assign) int maxTrackFaces; // 设置最大的人脸跟踪个数 default is 1
|
||||
|
||||
@property (nonatomic, assign, readonly) int trackedFacesCount; // 跟踪到的人脸个数
|
||||
|
||||
@property (nonatomic, assign) int maxTrackBodies; // 设置最大的人体跟踪个数 default is 1
|
||||
|
||||
@property (nonatomic, assign) FUFaceProcessorDetectMode faceProcessorDetectMode; // 人脸检测模式 default is FUFaceProcessorDetectModeVideo
|
||||
|
||||
@property (nonatomic, assign) FUHumanProcessorDetectMode humanProcessorDetectMode; // 人体检测模式,default is FUHumanProcessorDetectModeVideo
|
||||
|
||||
@property (nonatomic, assign) BOOL faceProcessorSetFaceLandmarkHpOccu; // 遮挡点位是否使用高精度模型, 默认YES,YES 高精度模型,NO 通用模型
|
||||
|
||||
@property (nonatomic, assign) BOOL faceProcessorDetectSmallFace; // 是否开启小脸检测,default is NO
|
||||
|
||||
@property (nonatomic, assign) BOOL asyncTrackFace; //设置是否进行异步人脸跟踪
|
||||
|
||||
@property (nonatomic, assign) BOOL faceRaceDetect; // 人种检测是否开启,默认关闭
|
||||
|
||||
@property (nonatomic, assign) FUFaceProcessorFaceLandmarkQuality faceProcessorFaceLandmarkQuality; // 人脸算法质量
|
||||
|
||||
+ (instancetype)shareKit;
|
||||
|
||||
/// 人脸模型设置
|
||||
/// @param config 枚举值
|
||||
/// @note 必须在加载 AI 人脸模型之前设置
|
||||
+ (void)setFaceModelConfig:(FUFaceModelConfig)config;
|
||||
|
||||
/// 人脸算法设置
|
||||
/// @param config 枚举值
|
||||
/// @note 必须在加载 AI 人脸模型之前设置,默认 FUFaceAlgorithmConfigEnableAll
|
||||
+ (void)setFaceAlgorithmConfig:(FUFaceAlgorithmConfig)config;
|
||||
|
||||
/// 人体模型设置
|
||||
/// @param config 枚举值
|
||||
/// @note 必须在加载 AI 人体模型之前设置,默认 FUHumanSegmentationModeCPUCommon
|
||||
+ (void)setHumanModelConfig:(FUHumanSegmentationMode)config;
|
||||
|
||||
/// 人体算法设置
|
||||
/// @param config 枚举值
|
||||
/// @note 必须在加载 AI 人脸模型之前设置,默认 FUHumanAlgorithmConfigEnableAll
|
||||
+ (void)setHumanAlgorithmConfig:(FUHumanAlgorithmConfig)config;
|
||||
|
||||
/// 强制设置使用 CPU 运行 AI 模型
|
||||
/// @note 必须在加载 AI 模型之前设置
|
||||
+ (void)setModelToCPU;
|
||||
|
||||
/// 加载AI模型
|
||||
/// @param type AI类型
|
||||
/// @param dataPath 模型路径
|
||||
+ (void)loadAIModeWithAIType:(FUAITYPE)type dataPath:(NSString *)dataPath;
|
||||
|
||||
/// 加载人体AI模型
|
||||
/// @param dataPath 模型路径
|
||||
/// @param mode 人体分割模式
|
||||
/// @note 使用 loadAIModeWithAIType:dataPath: 接口加载人体模型时默认的分割模式为 FUHumanSegmentationModeCPUCommon
|
||||
+ (void)loadAIHumanModelWithDataPath:(NSString *)dataPath segmentationMode:(FUHumanSegmentationMode)mode;
|
||||
|
||||
/// 卸载AI模型
|
||||
/// @param type AI 类型
|
||||
+ (void)unloadAIModeForAIType:(FUAITYPE)type;
|
||||
|
||||
/// 卸载所有的AI模型
|
||||
+ (void)unloadAllAIMode;
|
||||
|
||||
/// 判断某 AI 模型是否加载
|
||||
/// @param type AI 类型
|
||||
+ (BOOL)loadedAIType:(FUAITYPE)type;
|
||||
|
||||
/// 加载舌头模型
|
||||
/// @param modePath 舌头模型地址
|
||||
+ (void)loadTongueMode:(NSString *)modePath;
|
||||
|
||||
/// 设置 AI 识别类型
|
||||
/// @param type AI 识别类型
|
||||
+ (void)setTrackFaceAIType:(FUAITYPE)type;
|
||||
|
||||
/// 对输入的图像进行 AI 识别,支持人脸、身体、手指能类型的识别
|
||||
+ (int)trackFaceWithInput:(FUTrackFaceInput *)trackFaceInput;
|
||||
|
||||
/// 图像明显发生改变时调用该接口重置内部检测结果
|
||||
+ (void)resetTrackedResult;
|
||||
|
||||
/// 跟踪到的人脸数量
|
||||
+ (int)aiFaceProcessorNums;
|
||||
|
||||
/// 设置面部参数
|
||||
+ (void)setFaceTrackParam:(NSString *)param value:(int)value;
|
||||
|
||||
/**
|
||||
获取人脸信息:
|
||||
- 在程序中需要先运行过视频处理接口( 视频处理接口8 除外)或 人脸信息跟踪接口
|
||||
后才能使用该接口来获取人脸信息;
|
||||
-
|
||||
该接口能获取到的人脸信息与我司颁发的证书有关,普通证书无法通过该接口获取到人脸信息;
|
||||
- 具体参数及证书要求如下:
|
||||
|
||||
landmarks: 2D人脸特征点,返回值为75个二维坐标,长度75*2
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
landmarks_ar: 3D人脸特征点,返回值为75个三维坐标,长度75*3
|
||||
证书要求: AVATAR证书
|
||||
|
||||
rotation: 人脸三维旋转,返回值为旋转四元数,长度4
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
translation: 人脸三维位移,返回值一个三维向量,长度3
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
eye_rotation: 眼球旋转,返回值为旋转四元数,长度4
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
rotation_raw: 人脸三维旋转(不考虑屏幕方向),返回值为旋转四元数,长度4
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
expression: 表情系数,长度46
|
||||
证书要求: AVATAR证书
|
||||
|
||||
projection_matrix: 投影矩阵,长度16
|
||||
证书要求: AVATAR证书
|
||||
|
||||
face_rect: 人脸矩形框,返回值为(xmin,ymin,xmax,ymax),长度4
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
rotation_mode: 人脸朝向,0-3分别对应手机四种朝向,长度1
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
@param faceId 被检测的人脸 ID ,未开启多人检测时传 0
|
||||
,表示检测第一个人的人脸信息;当开启多人检测时,其取值范围为 [0 ~ maxFaces-1]
|
||||
,取其中第几个值就代表检测第几个人的人脸信息
|
||||
@param name 人脸信息参数名: "landmarks" , "eye_rotation" , "translation" ,
|
||||
"rotation" ....
|
||||
@param pret 作为容器使用的 float 数组指针,获取到的人脸信息会被直接写入该 float
|
||||
数组。
|
||||
@param number float 数组的长度
|
||||
@return 返回 1 代表获取成功,返回 0 代表获取失败
|
||||
*/
|
||||
+ (int)getFaceInfo:(int)faceId
|
||||
name:(NSString *)name
|
||||
pret:(float *)pret
|
||||
number:(int)number;
|
||||
|
||||
|
||||
/*
|
||||
* 获取人种分类
|
||||
* faceId 被检测的人脸 ID ,未开启多人检测时传 0
|
||||
* return -1:unknow, 0:black, 1:white, 2:yellow, 3:brown
|
||||
*/
|
||||
+ (int)getFaceRace:(int)faceId;
|
||||
|
||||
/// 设置了InputCameraMatrix之后获取获取人脸信息
|
||||
+ (int)getRotatedFaceInfo:(int)faceId
|
||||
name:(NSString *)name
|
||||
pret:(float *)pret
|
||||
number:(int)number;
|
||||
|
||||
/// 人脸检测置信度
|
||||
/// @param index 人脸索引
|
||||
+ (float)fuFaceProcessorGetConfidenceScore:(int)index;
|
||||
|
||||
/// 设置跟踪到人脸时每次检测的间隔帧数
|
||||
/// @param frames 帧数
|
||||
/// @note 底层默认间隔帧数为7
|
||||
+ (void)setFaceProcessorDetectEveryFramesWhenFace:(int)frames;
|
||||
|
||||
/// 设置未跟踪到人脸时每次检测的间隔帧数
|
||||
/// @param frames 帧数
|
||||
/// @note 底层默认间隔帧数为7
|
||||
+ (void)setFaceProcessorDetectEveryFramesWhenNoFace:(int)frames;
|
||||
|
||||
/// 设置人脸离开延迟打开或关闭
|
||||
/// @param enable YES为打开 NO为关闭
|
||||
+ (void)setFaceDelayLeaveEnable:(BOOL)enable;
|
||||
|
||||
/// 跟踪到的人体数量
|
||||
+ (int)aiHumanProcessorNums;
|
||||
|
||||
/// 重置身体识别
|
||||
+ (void)resetHumanProcessor;
|
||||
|
||||
/// 设置人体分割场景类型
|
||||
+ (void)setHumanSegmentationSceneType:(FUHumanSegmentationSceneType)type __attribute__((deprecated("Use loadAIHumanModelWithDataPath: segmentationMode: instead.")));
|
||||
|
||||
/// 跟踪到的手势数量
|
||||
+ (int)aiHandDistinguishNums;
|
||||
|
||||
/// 获取手势类型
|
||||
/// @param handIndex aiHandDistinguishNums返回手的索引
|
||||
+ (FUAIGESTURETYPE)fuHandDetectorGetResultGestureType:(int)handIndex;
|
||||
|
||||
/// 设置未跟踪到手势时每次检测的间隔帧数
|
||||
/// @param frames 帧数
|
||||
+ (void)setHandDetectEveryFramesWhenNoHand:(int)frames;
|
||||
|
||||
/// 动作识别: actionId index of fuHumanProcessorGetNumResults
|
||||
+ (int)fuHumanProcessorGetResultActionType:(int)actionId;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface FUAIKit (Test)
|
||||
|
||||
@property (nonatomic, assign) float use_new_cnn_detection;
|
||||
@property (nonatomic, assign) float other_face_detection_frame_step_new;
|
||||
@property (nonatomic, assign) float min_facesize_big;
|
||||
@property (nonatomic, assign) float small_face_frame_step;
|
||||
@property (nonatomic, assign) float min_facesize_small;
|
||||
|
||||
@property (nonatomic, assign) float other_face_detection_frame_step;
|
||||
@property (nonatomic, assign) float size_min;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - FUTrackFaceInput
|
||||
|
||||
@interface FUTrackFaceConfig : NSObject
|
||||
/// 是否进行舌头的检测,默认不对舌头进行检测。
|
||||
@property (nonatomic, assign) BOOL trackTongue;
|
||||
|
||||
@property (nonatomic, assign) FUImageOrientation imageOrientation; // 设置人物在原始图像中的方向,默认为 FUImageOrientationUP。
|
||||
|
||||
@property (nonatomic, assign) BOOL gravityEnable; // 重力开关,开启此功能可以根据已设置的 trackOrientation 自动适配AI检测的方向。
|
||||
|
||||
|
||||
/// 当前图片是否来源于前置摄像头,默认为 NO
|
||||
@property (nonatomic, assign) BOOL isFromFrontCamera;
|
||||
|
||||
/// 当前图片是否来源于镜像摄像头,默认为 NO
|
||||
@property (nonatomic, assign) BOOL isFromMirroredCamera;
|
||||
@end
|
||||
|
||||
/// trackFaceWithInput 接口的输入,CVPixelBufferRef、FUImageBuffer只需要传入一个就好,如果传入多个,将按优先级使用其中一种,优先级为:CVPixelBufferRef > FUImageBuffer;
|
||||
@interface FUTrackFaceInput : NSObject
|
||||
/// 输入的 pixelBuffer
|
||||
@property (nonatomic, assign) CVPixelBufferRef pixelBuffer;
|
||||
|
||||
/// 输入的 imageBuffer
|
||||
@property (nonatomic, assign) FUImageBuffer imageBuffer;
|
||||
|
||||
/// 设置 trackFace 相关的输入配置,详细参数请查看 FUTrackFaceConfig 类的接口注释。
|
||||
@property (nonatomic, strong) FUTrackFaceConfig *trackFaceConfig;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// FUAISegmentItem.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/28.
|
||||
//
|
||||
|
||||
#import "FUSticker.h"
|
||||
#import "FUStruct.h"
|
||||
#import "UIImage+FURenderKit.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
/**
|
||||
* 人像分割道具
|
||||
*/
|
||||
@interface FUAISegment : FUSticker
|
||||
|
||||
/// 摄像机切换前后需要设置
|
||||
@property (nonatomic, assign) int cameraMode;
|
||||
|
||||
/// 轮廓分割线和人体的间距
|
||||
@property (nonatomic, assign) double lineGap;
|
||||
|
||||
/// 轮廓分割线宽度
|
||||
@property (nonatomic, assign) double lineSize;
|
||||
|
||||
/// 轮廓分割线颜色
|
||||
/// @note 忽略alpha
|
||||
@property (nonatomic, assign) FUColor lineColor;
|
||||
|
||||
/// 自定义背景图片
|
||||
@property (nonatomic, strong) UIImage *backgroundImage;
|
||||
|
||||
/// 自定义背景视频
|
||||
/// @note NSURL or NSString,设置以后自动开始播放
|
||||
@property (nonatomic, copy) id videoPath; // 背景视频
|
||||
|
||||
/// 背景视频是否播放
|
||||
@property (nonatomic, assign) BOOL pause;
|
||||
|
||||
/// 开始背景视频播放
|
||||
- (void)startVideoDecode;
|
||||
|
||||
/// 取消背景视频播放
|
||||
- (void)stopVideoDecode;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// FUActionRecognition.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/18.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUActionRecognition : FUItem
|
||||
@property (nonatomic, assign) double edgeDistance;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// FUAnimation.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/16.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
|
||||
@interface FUAnimation : FUItem
|
||||
|
||||
+ (instancetype)animationWithPath:(NSString *)path name:(NSString *)name;
|
||||
|
||||
- (NSArray *)getAllAnimations;
|
||||
|
||||
- (NSArray *)getAllItems;
|
||||
@end
|
||||
22
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUAnimoji.h
Executable file
22
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUAnimoji.h
Executable file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// FUAnimoji.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/28.
|
||||
//
|
||||
|
||||
#import "FUSticker.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
/**
|
||||
* FUAnimoji 表情
|
||||
*/
|
||||
@interface FUAnimoji : FUSticker
|
||||
/**
|
||||
* NO 不跟随,YES 跟随
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL flowEnable;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
245
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUAvatar.h
Executable file
245
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUAvatar.h
Executable file
@@ -0,0 +1,245 @@
|
||||
//
|
||||
// FUAvatar.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/16.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
#import "FUAnimation.h"
|
||||
#import "FUStruct.h"
|
||||
#import "FUFacepupKeys.h"
|
||||
#import "FUDeformationKeys.h"
|
||||
#import "FUAvatarColorKeys.h"
|
||||
#import "FUAvatarMakeup.h"
|
||||
#import "CNamaSDK.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUAvatar : FURenderableObject
|
||||
|
||||
@property (nonatomic, assign) FUPosition position;
|
||||
|
||||
@property (nonatomic, assign) BOOL visible;
|
||||
|
||||
@property (nonatomic, assign) double rotate;
|
||||
|
||||
/// 身体组件列表
|
||||
@property (nonatomic, copy, readonly) NSArray<FUItem *> *components;
|
||||
|
||||
/// 当前正在播放的动画
|
||||
@property (nonatomic, strong, readonly) FUAnimation *currentAnimation;
|
||||
|
||||
/// 动画列表
|
||||
@property (nonatomic, copy, readonly) NSArray<FUAnimation *> *animations;
|
||||
|
||||
@property (nonatomic, assign) int faceTrackID;
|
||||
|
||||
// 阴影
|
||||
@property (nonatomic, assign) double shadowPCFLevel;
|
||||
|
||||
@property (nonatomic, assign) int shadowSampleOffset;
|
||||
|
||||
- (void)updateTransformWithTranslateDelta:(float)translateDelta rotateDelta:(float)rotateDelta scaleDelta:(float)scaleDelta;
|
||||
|
||||
/// 通过Avatar的名称获取Avatar信息的Json字符串
|
||||
/// @param name Avatar的名称
|
||||
- (NSString *)avatarJsonWithName:(NSString *)name;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAvatar (Component)
|
||||
|
||||
/// 添加身体组件,如果组件的 name 不为空,可以通过 name 查找或移除组件;如果 avatar 已有组件存在与新组件名称一致的组件,已存在的组件将被替换。
|
||||
/// @param component 身体组件
|
||||
- (void)addComponent:(FUItem *)component;
|
||||
|
||||
- (BOOL)replaceComponent:(FUItem *)component withNewComponent:(FUItem *)newComponent;
|
||||
|
||||
- (BOOL)replaceComponentWithName:(NSString *)name newComponent:(FUItem *)newComponent;
|
||||
|
||||
|
||||
/// 批量添加和移除接口,如果 avatar 已有组件与新组件数组中存在名称一致的组件,已存在的组件将被替换。
|
||||
/// @param newComponents 新的组件数组
|
||||
/// @param removeComponentNames 老组件名字数组
|
||||
- (void)addNewComponents:(NSArray<FUItem *> *)newComponents withRemoveComponentNames:(NSArray<NSString *> *)removeComponentNames ;
|
||||
|
||||
/// 批量添加和移除接口,如果 avatar 已有组件与新组件数组中存在名称一致的组件,已存在的组件将被替换。
|
||||
/// @param newComponents 新的组件数组
|
||||
/// @param removeComponentFileIds 老组件fileId数组
|
||||
- (void)addNewComponents:(NSArray<FUItem *> *)newComponents withRemoveComponentFileIds:(NSArray<NSString *> *)removeComponentFileIds;
|
||||
|
||||
/// 通过组件名称查找组件
|
||||
/// @param componentName 组件名称
|
||||
- (FUItem *)componentForName:(NSString *)componentName;
|
||||
|
||||
/// 移除身体组件
|
||||
/// @param component 身体组件
|
||||
- (void)removeComponent:(FUItem *)component;
|
||||
|
||||
/// 通过身体组件名称移除组件
|
||||
/// @param componentName 组件名称
|
||||
- (FUItem*)removeComponentWithName:(NSString *)componentName;
|
||||
|
||||
- (void)updateComponentsVisiableWithARMode:(BOOL)ARMode;
|
||||
|
||||
/// 处理选中多个道具时的互斥协同逻辑
|
||||
/// @param fileIds 道具fileId 集合
|
||||
/// @param assetRootPath 资源跟路径
|
||||
- (void)handleExcludeAndAssociateWithFileIds:(NSArray<NSString *> *)fileIds assetRootPath:(NSString *)assetRootPath;
|
||||
|
||||
/// 处理选中多个道具时的互斥协同逻辑
|
||||
/// @param fileIds 道具fileId 集合
|
||||
/// @param assetRootPath 资源跟路径
|
||||
/// @param instanceId Avatar实例id
|
||||
/// @param avatar avatar
|
||||
+ (void)handleExcludeAndAssociateWithFileIds:(NSArray<NSString *> *)fileIds assetRootPath:(NSString *)assetRootPath instanceId:(int)instanceId avatar:(FUAvatar *)avatar;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAvatar (Animation)
|
||||
|
||||
@property (nonatomic, assign) BOOL enableAnimationLerp;
|
||||
|
||||
/// 添加动画,如果动画的 name 不为空,可以通过 name 查找或移除动画
|
||||
/// @param animation 动画
|
||||
- (void)addAnimation:(FUAnimation *)animation;
|
||||
|
||||
/// 通过动画名称查找动画
|
||||
/// @param animationName 动画名称
|
||||
- (FUAnimation *)animationForName:(NSString *)animationName;
|
||||
|
||||
/// 移除动画
|
||||
/// @param animation 动画
|
||||
- (void)removeAnimation:(FUAnimation *)animation;
|
||||
|
||||
/// 通过名称移除动画
|
||||
/// @param animationName 动画名称
|
||||
- (void)removeAnimationWithName:(NSString *)animationName;
|
||||
|
||||
/// 移除所有动画
|
||||
- (void)removeAllAnimations;
|
||||
|
||||
/// 播放动画
|
||||
/// @param animation 动画
|
||||
/// @param playOnce YES 只播放一次,NO 循环播放
|
||||
/// @param transitionDuration 动画过度时间
|
||||
- (void)playAnimation:(nullable FUAnimation *)animation playOnce:(BOOL)playOnce transitionDuration:(float)transitionDuration;
|
||||
|
||||
/// 通过名称播放动画
|
||||
/// @param animationName 动画名称
|
||||
/// @param playOnce YES 只播放一次,NO 循环播放
|
||||
/// @param transitionDuration 动画过度时间
|
||||
- (void)playAnimationWithName:(NSString *)animationName playOnce:(BOOL)playOnce transitionDuration:(float)transitionDuration;
|
||||
|
||||
- (void)pauseCurrentAnimation;
|
||||
|
||||
- (void)resumeCurrentAnimation;
|
||||
|
||||
- (void)stopCurrentAnimation;
|
||||
|
||||
- (void)resetCurrentAnimation;
|
||||
|
||||
- (double)getProgressForAnimation:(FUAnimation *)animation;
|
||||
|
||||
- (double)getTransitionProgressForAnimation:(FUAnimation *)animation;
|
||||
|
||||
- (int)getFrameNumberForAnimation:(FUAnimation *)animation;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAvatar (DynamicBone)
|
||||
|
||||
@property (nonatomic, assign) BOOL modelmatToBone;
|
||||
@property (nonatomic, assign) BOOL dynamicBoneTeleportMode;
|
||||
@property (nonatomic, assign) BOOL dynamicBoneRootTranslateSpeedLimitMode;
|
||||
@property (nonatomic, assign) BOOL dynamicBoneRootRotateSpeedLimitMode;
|
||||
- (void)refreshDynamicBone;
|
||||
- (void)resetDynamicBone;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAvatar (Blendshape)
|
||||
|
||||
@property (nonatomic, assign) BOOL enableExpressionBlend;
|
||||
|
||||
@property (nonatomic) FUBlendshapeWeight inputBlendshapeWeight;
|
||||
|
||||
@property (nonatomic) FUBlendshapeWeight systemBlendshapeWeight;
|
||||
|
||||
- (void)updateInputBlendshape:(FUBlendshape)blendshape;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAvatar (EyesFocusToCamera)
|
||||
|
||||
@property (nonatomic, assign) BOOL eyesFocusToCamera;
|
||||
|
||||
@property (nonatomic, assign) double eyesFocusHeightAdjust;
|
||||
|
||||
@property (nonatomic, assign) double eyesFocusDistanceAdjust;
|
||||
|
||||
@property (nonatomic, assign) double eyesFocusWeight;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAvatar (Color)
|
||||
|
||||
- (NSDictionary <NSString *, NSData *> *)allColorKeyValues;
|
||||
|
||||
- (NSDictionary<NSString *,NSNumber *> *)allColorIntensityKeyValues;
|
||||
|
||||
- (void)setColor:(FURGBColor)color forComponentName:(NSString *)componentName;
|
||||
|
||||
- (void)setColor:(FURGBColor)color forKey:(NSString *)colorKey;
|
||||
|
||||
- (void)setColorIntensity:(float)colorIntensity forKey:(NSString *)colorIntensityKey;
|
||||
|
||||
- (int)getSkinColorIndex;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAvatar (Facepup)
|
||||
|
||||
@property (nonatomic, copy, readonly) NSArray<NSNumber *> *allFacepupValues;
|
||||
|
||||
@property (nonatomic, copy, readonly) NSDictionary<NSString *, NSNumber *> *allFacepupKeyValues;
|
||||
|
||||
+ (void)setFacepupKeysWithJsonPath:(NSString *)josnPath;
|
||||
|
||||
- (void)enterFacepupMode;
|
||||
|
||||
- (void)quitFacepupMode;
|
||||
|
||||
- (void)setFacepupValue:(double)facepupValue forKey:(NSString *)facepupKey;
|
||||
|
||||
- (CGPoint)getFaceVertexScreenCoordinateForVertexIndex:(int)index;
|
||||
|
||||
- (float)getFacepupOriginalValueForKey:(NSString *)facepupKey;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAvatar (HumanAnimDriver)
|
||||
|
||||
-(void)setEnableHumanAnimDriver:(BOOL)enableHumanAnimDriver;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAvatar (Deformation)
|
||||
|
||||
@property (nonatomic, copy, readonly) NSDictionary<NSString *, NSNumber *> *allDeformationKeyValues;
|
||||
|
||||
- (void)setDeformationValue:(double)deformationValue forKey:(NSString *)deformationKey;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUAvatar (BodyTrack)
|
||||
|
||||
@property (nonatomic, assign) FUAIHUMANFOLLOWMODE bodyFollowMode;
|
||||
|
||||
@property (nonatomic, assign) BOOL bodyTrackEnable;
|
||||
|
||||
@property (nonatomic, assign) int humanProcessorType; // 身体数据的来源类型
|
||||
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// FUAvatarCheck.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by 刘保健 on 2021/12/30.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUAvatar.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUAvatarCheck : NSObject
|
||||
|
||||
+ (FUAvatarCheck *)initWithControllerConfigPath:(NSString *)controllerConfigPath litemListJson:(NSString *)litemListJson;
|
||||
|
||||
- (void)checkAvatarComponentFileIds:(NSArray <NSString *>*)fileIds avatar:(FUAvatar *)avatar assetRootPath:(NSString *)assetRootPath;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// FUAvatarColorKeys.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by liuyang on 2021/2/18.
|
||||
//
|
||||
|
||||
//FUParamsKeysDefine(FUAvatarColor,
|
||||
// // 颜色
|
||||
// FUAvatarColorSkinColor = @"skin_color", // 肤色
|
||||
// FUAvatarColorIrisColor = @"iris_color", // 瞳孔颜色
|
||||
// FUAvatarColorGlassColor = @"glass_color", // 眼镜片颜色
|
||||
// FUAvatarColorGlassFrameColor = @"glass_frame_color", // 眼镜框颜色
|
||||
// FUAvatarColorHairColor = @"hair_color", // 头发颜色
|
||||
// FUAvatarColorLipColor = @"makeup_lipgloss_color", // 头发颜色
|
||||
// FUAvatarColorLipColor12 = @"makeup_eyelash_color", // 头发颜色
|
||||
// )
|
||||
//
|
||||
//FUParamsKeysDefine(FUAvatarColorIntensity,
|
||||
// // 颜色强度
|
||||
// FUAvatarColorIntensityHair = @"hair_color_intensity" // 头发颜色强度
|
||||
// )
|
||||
//
|
||||
//FUParamsKeysDefine(FUAvatarColorIndex,
|
||||
// // 颜色索引
|
||||
// FUAvatarColorIndexSkin = @"skin_color_index", // 当前肤色在肤色表的索引,从0开始
|
||||
// FUAvatarColorIndexLip = @"lip_color_index" // 当前唇色在唇色表的索引,从0开始
|
||||
// )
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// FUAvatarMakeup.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/25.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
#import "FUStruct.h"
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUAvatarMakeup : FUItem
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// FUBackGround.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/16.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUBackground : FUItem
|
||||
|
||||
@property (nonatomic, assign) BOOL supportFollowBodyMode; // 身体驱动时是否支持跟随身体模式
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// FUBeauty-Deprecated.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by 项林平 on 2022/3/29.
|
||||
//
|
||||
|
||||
#import "FUBeauty.h"
|
||||
|
||||
@interface FUBeauty (Deprecated)
|
||||
|
||||
@property (nonatomic, assign) double cheekNarrowV2 DEPRECATED_MSG_ATTRIBUTE("use cheekNarrow instead");//窄脸 取值范围 0.0-1.0, 0.0为无效果,1.0为最大效果,默认值0.0
|
||||
@property (nonatomic, assign) double cheekSmallV2 DEPRECATED_MSG_ATTRIBUTE("use cheekSmall instead");//小脸 取值范围 0.0-1.0, 0.0为无效果,1.0为最大效果,默认值0.0
|
||||
@property (nonatomic, assign) double eyeEnlargingV2 DEPRECATED_MSG_ATTRIBUTE("use eyeEnlarging instead");//大眼 取值范围 0.0-1.0, 0.0为无效果,1.0为最大效果,默认值0.0
|
||||
@property (nonatomic, assign) double intensityForeheadV2 DEPRECATED_MSG_ATTRIBUTE("use intensityForehead instead");//额头 取值范围 0.0-1.0, 0.5-0.0是变小,0.5-1.0是变大,默认值0.5
|
||||
@property (nonatomic, assign) double intensityNoseV2 DEPRECATED_MSG_ATTRIBUTE("use intensityNose instead");//瘦鼻 取值范围 0.0-1.0, 0.0为无效果,1.0为最大效果,默认值0.0
|
||||
@property (nonatomic, assign) double intensityMouthV2 DEPRECATED_MSG_ATTRIBUTE("use intensityMouth instead");//嘴型 取值范围 0.0-1.0, 0.5-0.0是变大,0.5-1.0是变小,默认值0.5
|
||||
|
||||
@end
|
||||
217
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUBeauty.h
Executable file
217
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUBeauty.h
Executable file
@@ -0,0 +1,217 @@
|
||||
//
|
||||
// FUBeauty.m
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by 项林平 on 2023/5/16.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
#import "FUFilterDefineKey.h"
|
||||
#import "FUBeautyPropertyModeDefine.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUBeauty : FUItem
|
||||
|
||||
/// 磨皮是否使用 mask
|
||||
@property (nonatomic, assign) BOOL blurUseMask;
|
||||
|
||||
/// 朦胧磨皮开关 0清晰磨皮 1朦胧磨皮
|
||||
@property (nonatomic, assign) int heavyBlur;
|
||||
|
||||
/// 磨皮类型 0清晰磨皮 1朦胧磨皮 2精细磨皮 3均匀磨皮
|
||||
/// @note 此属性优先级比 heavyBlur 低, 在使用时要将 heavyBlur 设为0
|
||||
@property (nonatomic, assign) int blurType;
|
||||
|
||||
/// 将所有属性恢复到默认值
|
||||
- (void)resetToDefault;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface FUBeauty (Skin)
|
||||
|
||||
/// 皮肤分割(皮肤美白),YES开启,NO关闭,默认NO
|
||||
/// @note 开启时美白效果仅支持皮肤区域,关闭时美白效果支持全局区域
|
||||
/// @note 推荐非直播场景和 iPhoneXR 以上机型使用
|
||||
@property (nonatomic, assign) BOOL enableSkinSegmentation;
|
||||
|
||||
/// 肤色检测开关 0为关, 1为开,默认值0.0
|
||||
@property (nonatomic, assign) int skinDetect;
|
||||
|
||||
/// 肤色检测之后非肤色区域的融合程度 取值范围0.0-1.0,默认值0.0
|
||||
@property (nonatomic, assign) int nonskinBlurScale;
|
||||
|
||||
/// 精细磨皮 取值范围0.0-6.0, 默认6.0
|
||||
@property (nonatomic, assign) double blurLevel;
|
||||
|
||||
/// 祛斑痘,取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
/// @note 硬件支持原因,祛斑痘仅支持 iPhoneXR 及以上机型使用
|
||||
@property (nonatomic, assign) double antiAcneSpot;
|
||||
|
||||
/// 美白 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double colorLevel;
|
||||
|
||||
/// 红润 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double redLevel;
|
||||
|
||||
/// 清晰 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double clarity;
|
||||
|
||||
/// 锐化 取值范围0.0-1.0, 默认0.0
|
||||
@property (nonatomic, assign) double sharpen;
|
||||
|
||||
/// 五官立体 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double faceThreed;
|
||||
|
||||
/// 亮眼 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double eyeBright;
|
||||
|
||||
/// 美牙 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double toothWhiten;
|
||||
|
||||
/// 去黑眼圈 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double removePouchStrength;
|
||||
|
||||
/// 去法令纹 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double removeNasolabialFoldsStrength;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUBeauty (Shape)
|
||||
|
||||
/// 变形取值 0女神变形 1网红变形 2自然变形 3默认变形 4精细变形
|
||||
@property (nonatomic, assign) int faceShape;
|
||||
|
||||
/// 渐变所需要的帧数 0为关闭渐变, 大于0开启渐变
|
||||
@property (nonatomic, assign) int changeFrames;
|
||||
|
||||
/// 变形程度 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值1.0
|
||||
@property (nonatomic, assign) double faceShapeLevel;
|
||||
|
||||
/// v脸 0.0-1.0,默认0.0
|
||||
@property (nonatomic, assign) double cheekV;
|
||||
|
||||
/// 瘦脸 0.0-1.0,默认0.0
|
||||
@property (nonatomic, assign) double cheekThinning;
|
||||
|
||||
/// 长脸 0.0-1.0,默认0.0
|
||||
@property (nonatomic, assign) double cheekLong;
|
||||
|
||||
/// 圆脸 0.0-1.0,默认0.0
|
||||
@property (nonatomic, assign) double cheekCircle;
|
||||
|
||||
/// 窄脸 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double cheekNarrow;
|
||||
|
||||
/// 小脸 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double cheekSmall;
|
||||
|
||||
/// 短脸 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double cheekShort;
|
||||
|
||||
/// 瘦颧骨 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double intensityCheekbones;
|
||||
|
||||
/// 瘦下颌骨 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double intensityLowerJaw;
|
||||
|
||||
/// 大眼 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double eyeEnlarging;
|
||||
|
||||
/// 下巴 取值范围 0.0-1.0, 0.5-0是变小, 0.5-1是变大, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityChin;
|
||||
|
||||
/// 额头 取值范围 0.0-1.0, 0.5-0是变小, 0.5-1是变大, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityForehead;
|
||||
|
||||
/// 瘦鼻 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double intensityNose;
|
||||
|
||||
/// 嘴型 取值范围 0.0-1.0, 0.5-0.0是变大, 0.5-1.0是变小, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityMouth;
|
||||
|
||||
/// 嘴唇厚度 取值范围 0.0-1.0, 默认值0.5, 0.5-0是变薄, 0.5-1是变厚, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityLipThick;
|
||||
|
||||
/// 眼睛位置 取值范围 0.0-1.0, 默认值0.5, 0.5-0是变低, 0.5-1是变高, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityEyeHeight;
|
||||
|
||||
/// 开眼角 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double intensityCanthus;
|
||||
|
||||
/// 眼睑下至 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double intensityEyeLid;
|
||||
|
||||
/// 眼距 取值范围 0.0-1.0, 0.5-0.0是变大, 0.5-1.0是变小, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityEyeSpace;
|
||||
|
||||
/// 眼睛角度 取值范围 0.0-1.0, 0.5-0.0逆时针旋转, 0.5-1.0顺时针旋转, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityEyeRotate;
|
||||
|
||||
/// 长鼻 取值范围 0.0-1.0, 0.5-0.0是变长, 0.5-1.0是变短, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityLongNose;
|
||||
|
||||
/// 缩人中 取值范围 0.0-1.0, 0.5-0.0是变短, 0.5-1.0是变长, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityPhiltrum;
|
||||
|
||||
/// 微笑嘴角 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double intensitySmile;
|
||||
|
||||
/// 圆眼 取值范围 0.0-1.0, 0.0为无效果, 1.0为最大效果, 默认值0.0
|
||||
@property (nonatomic, assign) double intensityEyeCircle;
|
||||
|
||||
/// 眉毛上下 取值范围 0.0-1.0, 0.5-0是向上, 0.5-1是向下, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityBrowHeight;
|
||||
|
||||
/// 眉间距 取值范围 0.0-1.0, 默认值0.5, 0.5-0是变小, 0.5-1是变大, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityBrowSpace;
|
||||
|
||||
/// 眉毛粗细 取值范围 0.0-1.0, 默认值0.5, 0.5-0是变细, 0.5-1是变粗, 默认值0.5
|
||||
@property (nonatomic, assign) double intensityBrowThick;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUBeauty (Filter)
|
||||
|
||||
/// 滤镜名称 字符串类型,默认值为 "origin" , 即为使用原图效果
|
||||
/// @see FUFilter
|
||||
@property (nonatomic, strong) FUFilter filterName;
|
||||
|
||||
/// 滤镜程度值 取值范围 0.0-1.0,0.0为无效果, 1.0为最大效果, 默认值1.0
|
||||
@property (nonatomic, assign) double filterLevel;
|
||||
|
||||
/// 获取指定滤镜的程度值
|
||||
/// - Parameter filterForKey: 滤镜名称
|
||||
- (double)filterValueForKey:(NSString *)filterForKey;
|
||||
|
||||
/// 所有支持的滤镜名称字符串数组
|
||||
- (NSArray *)allFilterKeys;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUBeauty (Mode)
|
||||
|
||||
/**
|
||||
* 设置部分美颜属性的mode, 不同mode会有主观上会有不同效果
|
||||
* 必须在设置美颜各个属性值之前调用该接口
|
||||
* key和mode说明
|
||||
| key | 属性 | 支持的mode |
|
||||
| ------------- | -------- | ------------------------------------------------------------ |
|
||||
| color_level | 美白 | FUBeautyPropertyMode1, FUBeautyPropertyMode2(v8.2.0) |
|
||||
| remove_pouch_strength | 去黑眼圈 | FUBeautyPropertyMode1, FUBeautyPropertyMode2(v8.2.0, 高性能设备推荐) |
|
||||
| remove_nasolabial_folds_strength | 去法令纹 | FUBeautyPropertyMode1, FUBeautyPropertyMode2(v8.2.0, 高性能设备推荐) |
|
||||
| cheek_thinning | 瘦脸 | FUBeautyPropertyMode1, FUBeautyPropertyMode2(v8.3.0) |
|
||||
| cheek_narrow | 窄脸 | FUBeautyPropertyMode1, FUBeautyPropertyMode2(v8.0.0) |
|
||||
| cheek_small | 小脸 | FUBeautyPropertyMode1, FUBeautyPropertyMode2(v8.0.0) |
|
||||
| eye_enlarging | 大眼 | FUBeautyPropertyMode1, FUBeautyPropertyMode2(v8.0.0), FUBeautyPropertyMode3(v8.2.0, 高性能设备推荐) |
|
||||
| intensity_chin | 下巴 | FUBeautyPropertyMode1, FUBeautyPropertyMode2(v8.4.0) |
|
||||
| intensity_forehead | 额头 | FUBeautyPropertyMode1, FUBeautyPropertyMode2(v8.0.0) |
|
||||
| intensity_nose | 瘦鼻 | FUBeautyPropertyMode1, FUBeautyPropertyMode2(v8.0.0) |
|
||||
| intensity_mouth | 嘴型 | FUBeautyPropertyMode1, FUBeautyPropertyMode2(v8.0.0), FUBeautyPropertyMode3(v8.2.0, 高性能设备推荐) |
|
||||
**/
|
||||
- (void)addPropertyMode:(FUBeautyPropertyMode)mode forKey:(FUModeKey)key;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// FUBeautyPropertyModeDefine.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by 项林平 on 2022/3/29.
|
||||
//
|
||||
|
||||
#ifndef FUBeautyPropertyModeDefine_h
|
||||
#define FUBeautyPropertyModeDefine_h
|
||||
|
||||
#import "FUKeysDefine.h"
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FUBeautyPropertyMode) {
|
||||
FUBeautyPropertyMode1 = 1,
|
||||
FUBeautyPropertyMode2 = 2,
|
||||
FUBeautyPropertyMode3 = 3
|
||||
};
|
||||
|
||||
FUParamsKeysDefine(FUModeKey,
|
||||
FUModeKeyColorLevel = @"color_level",
|
||||
FUModeKeyRemovePouchStrength = @"remove_pouch_strength",
|
||||
FUModeKeyRemoveNasolabialFoldsStrength = @"remove_nasolabial_folds_strength",
|
||||
FUModeKeyCheekThinning = @"cheek_thinning",
|
||||
FUModeKeyCheekNarrow = @"cheek_narrow",
|
||||
FUModeKeyCheekSmall = @"cheek_small",
|
||||
FUModeKeyEyeEnlarging = @"eye_enlarging",
|
||||
FUModeKeyIntensityChin = @"intensity_chin",
|
||||
FUModeKeyIntensityForehead = @"intensity_forehead",
|
||||
FUModeKeyIntensityNose = @"intensity_nose",
|
||||
FUModeKeyIntensityMouth = @"intensity_mouth"
|
||||
)
|
||||
|
||||
|
||||
#endif /* FUBeautyPropertyModeDefine_h */
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// FUBodyBeauty.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/15.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@interface FUBodyBeauty : FUItem
|
||||
@property (nonatomic, assign) double bodySlimStrength; //瘦身
|
||||
@property (nonatomic, assign) double legSlimStrength; //长腿
|
||||
@property (nonatomic, assign) double waistSlimStrength; //瘦腰
|
||||
@property (nonatomic, assign) double shoulderSlimStrength; //美肩
|
||||
@property (nonatomic, assign) double hipSlimStrength; //美臀
|
||||
@property (nonatomic, assign) double headSlim; //小头
|
||||
@property (nonatomic, assign) double legSlim; //瘦腿
|
||||
@property (nonatomic, assign) int debug; //是否开启debug点位
|
||||
@property (nonatomic, assign) int clearSlim; //重置:清空所有的美体效果,恢复为默认值
|
||||
|
||||
/**
|
||||
* 取值范围 0 ~ 3
|
||||
*/
|
||||
@property (nonatomic, assign) int orientation;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// FUBodyBeautyDefineKeys.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by Chen on 2021/2/1.
|
||||
//
|
||||
|
||||
#ifndef FUBodyBeautyDefineKeys_h
|
||||
#define FUBodyBeautyDefineKeys_h
|
||||
|
||||
#import "FUKeysDefine.h"
|
||||
|
||||
FUParamsKeysDefine(FUBodyBeautyKey,
|
||||
|
||||
//瘦身
|
||||
FUBodyBeautyKeyBodySlimStrength = @"BodySlimStrength",
|
||||
|
||||
//长腿
|
||||
FUBodyBeautyKeyLegSlimStrength = @"LegSlimStrength",
|
||||
|
||||
//瘦腰
|
||||
FUBodyBeautyKeyWaistSlimStrength = @"WaistSlimStrength",
|
||||
|
||||
//长腿
|
||||
FUBodyBeautyKeyShoulderSlimStrength = @"ShoulderSlimStrength",
|
||||
|
||||
//美臀
|
||||
FUBodyBeautyKeyHipSlimStrength = @"HipSlimStrength",
|
||||
|
||||
//小头
|
||||
FUBodyBeautyKeyLegHeadSlim = @"HeadSlim",
|
||||
|
||||
//瘦腿
|
||||
FUBodyBeautyKeyLegSlim = @"LegSlim",
|
||||
)
|
||||
|
||||
#endif /* FUBodyBeautyDefineKeys_h */
|
||||
52
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUCLIColor.h
Executable file
52
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUCLIColor.h
Executable file
@@ -0,0 +1,52 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2020, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
// with or without modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Neither the name of Deusty nor the names of its contributors may be used
|
||||
// to endorse or promote products derived from this software without specific
|
||||
// prior written permission of Deusty, LLC.
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* This class represents an NSColor replacement for CLI projects that don't link with AppKit
|
||||
**/
|
||||
@interface FUCLIColor : NSObject
|
||||
|
||||
/**
|
||||
* Convenience method for creating a `FUCLIColor` instance from RGBA params
|
||||
*
|
||||
* @param red red channel, between 0 and 1
|
||||
* @param green green channel, between 0 and 1
|
||||
* @param blue blue channel, between 0 and 1
|
||||
* @param alpha alpha channel, between 0 and 1
|
||||
*/
|
||||
+ (instancetype)colorWithCalibratedRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;
|
||||
|
||||
/**
|
||||
* Get the RGBA components from a `FUCLIColor`
|
||||
*
|
||||
* @param red red channel, between 0 and 1
|
||||
* @param green green channel, between 0 and 1
|
||||
* @param blue blue channel, between 0 and 1
|
||||
* @param alpha alpha channel, between 0 and 1
|
||||
*/
|
||||
- (void)getRed:(nullable CGFloat *)red green:(nullable CGFloat *)green blue:(nullable CGFloat *)blue alpha:(nullable CGFloat *)alpha NS_SWIFT_NAME(get(red:green:blue:alpha:));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// FUCameraAnimation.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/24.
|
||||
//
|
||||
|
||||
#import "FUAnimation.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUCameraAnimation : FUAnimation
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// FUCamera.h
|
||||
// FUAPIDemo
|
||||
//
|
||||
// Created by liuyang on 2016/12/26.
|
||||
// Copyright © 2016年 liuyang. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
@class FUCaptureCamera;
|
||||
|
||||
@protocol FUCaptureCameraAudioDelegate <NSObject>
|
||||
|
||||
//音频
|
||||
- (void)didOutputAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer;
|
||||
|
||||
@end
|
||||
|
||||
@protocol FUCaptureCameraDelegate <NSObject>
|
||||
|
||||
-(void)didOutputVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer captureDevicePosition:(AVCaptureDevicePosition)position;
|
||||
|
||||
@end
|
||||
|
||||
@protocol FUCaptureCameraDataSource <NSObject>
|
||||
|
||||
- (CGPoint)fuCaptureFaceCenterInImage:(FUCaptureCamera *)camera ;
|
||||
|
||||
@end
|
||||
|
||||
typedef NS_ENUM( NSInteger, FUCaptureCameraFocusMode) {
|
||||
/* 先找人脸对焦模式 */
|
||||
FUCaptureCameraFocusModeAutoFace,
|
||||
/* 固定点对焦模式 */
|
||||
FUCaptureCameraFocusModeChangeless
|
||||
};
|
||||
|
||||
@interface FUCaptureCamera : NSObject
|
||||
@property (nonatomic, weak) id<FUCaptureCameraAudioDelegate> audioDelegate;
|
||||
@property (nonatomic, weak) id<FUCaptureCameraDelegate> delegate;
|
||||
@property (nonatomic, weak) id<FUCaptureCameraDataSource> dataSource;
|
||||
@property (nonatomic, assign, readonly) BOOL isFrontCamera;
|
||||
@property (nonatomic, assign, readonly) BOOL isMirrored;
|
||||
@property (nonatomic, assign, readonly) AVCaptureVideoOrientation videoOrientation;
|
||||
|
||||
@property (assign, nonatomic) int captureFormat; //采集格式
|
||||
@property (copy , nonatomic) dispatch_queue_t videoCaptureQueue;//视频采集的队列
|
||||
@property (copy , nonatomic) dispatch_queue_t audioCaptureQueue;//音频采集队列
|
||||
@property (copy , nonatomic) dispatch_queue_t tmpCaptureQueue;//视频采集的队列
|
||||
@property (assign, nonatomic) AVCaptureSessionPreset sessionPreset;
|
||||
@property (assign, nonatomic) BOOL needsAudioTrack;//是否需要音频,默认为NO
|
||||
|
||||
/// 是否正在采集
|
||||
@property (assign, nonatomic) BOOL capturing;
|
||||
|
||||
|
||||
- (instancetype)initWithCameraPosition:(AVCaptureDevicePosition)cameraPosition captureFormat:(int)captureFormat;
|
||||
|
||||
- (void)startCapture;
|
||||
|
||||
- (void)stopCapture;
|
||||
|
||||
- (void)changeCameraInputDeviceisFront:(BOOL)isFront;
|
||||
|
||||
- (void)takePhotoAndSave;
|
||||
|
||||
- (void)startRecord;
|
||||
|
||||
- (void)stopRecordWithCompletionHandler:(void (^)(NSString *videoPath))handler;
|
||||
|
||||
/* 当前分辨率是否支持前后置 */
|
||||
-(BOOL)supportsAVCaptureSessionPreset:(BOOL)isFront;
|
||||
|
||||
/**
|
||||
设置采集方向
|
||||
|
||||
@param orientation 方向
|
||||
*/
|
||||
- (void)setCaptureVideoOrientation:(AVCaptureVideoOrientation)orientation;
|
||||
|
||||
/**
|
||||
查询当前相机最大曝光补偿信息
|
||||
|
||||
@param current 当前
|
||||
@param max 最大
|
||||
@param min 最小
|
||||
*/
|
||||
- (void)getCurrentExposureValue:(float *)current max:(float *)max min:(float *)min;
|
||||
|
||||
/**
|
||||
恢复以屏幕中心自动连续对焦和曝光
|
||||
*/
|
||||
- (void)resetFocusAndExposureModes;
|
||||
|
||||
/// 修改采集分辨率
|
||||
/// @param sessionPreset 分辨率
|
||||
- (BOOL)changeSessionPreset:(AVCaptureSessionPreset)sessionPreset;
|
||||
|
||||
|
||||
/**
|
||||
修改采集视频镜像关系
|
||||
|
||||
@param videoMirrored videoMirrore
|
||||
*/
|
||||
- (void)changeVideoMirrored:(BOOL)videoMirrored;
|
||||
|
||||
/**
|
||||
修改帧率
|
||||
|
||||
在iOS上,使用AvCaptureDevice的setActiveFormat:和AvCaptureSession的setSessionPreset:是互斥的。
|
||||
如果 frameRate <= 30 setActiveFormat 则该设备所连接的会话将其预设更改为avCaptureSessionPresetinputPriority
|
||||
*/
|
||||
- (void)changeVideoFrameRate:(int)frameRate;
|
||||
|
||||
|
||||
- (void)setExposureValue:(float)value;
|
||||
|
||||
/// 设置曝光模式和兴趣点
|
||||
/// @param focusMode 对焦模式
|
||||
/// @param exposureMode 曝光模式
|
||||
/// @param point 兴趣点
|
||||
/// @param monitorSubjectAreaChange 是否监听主题变化
|
||||
- (void)focusWithMode:(AVCaptureFocusMode)focusMode exposeWithMode:(AVCaptureExposureMode)exposureMode atDevicePoint:(CGPoint)point monitorSubjectAreaChange:(BOOL)monitorSubjectAreaChange;
|
||||
|
||||
|
||||
/// 修改对焦模式
|
||||
/// @param mode 对焦模式
|
||||
- (void)cameraChangeMode:(FUCaptureCameraFocusMode)mode;
|
||||
|
||||
// 缩放
|
||||
// 可用于模拟对焦
|
||||
- (void)setZoomValue:(CGFloat)zoomValue;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// FUAnimationFIlterItem.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/13.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 动漫滤镜风格
|
||||
typedef NS_ENUM(NSInteger, FUComicFilterStyle) {
|
||||
FUComicFilterStyleNone = -1, // 无
|
||||
FUComicFilterStyleCartoon = 0, // 动漫
|
||||
FUComicFilterStyleSketch = 1, // 素描
|
||||
FUComicFilterStylePortrait = 2, // 人像
|
||||
FUComicFilterStylePainting = 3, // 油画
|
||||
FUComicFilterStyleSandPainting = 4, // 沙画
|
||||
FUComicFilterStylePenDrawing = 5, // 钢笔画
|
||||
FUComicFilterStylePencilDrawing = 6,// 铅笔画
|
||||
FUComicFilterStyleGraffiti = 7 // 涂鸦
|
||||
};
|
||||
|
||||
@interface FUComicFilter : FUItem
|
||||
|
||||
/// 动漫滤镜风格
|
||||
/// @see FUComicFilterStyle
|
||||
@property (nonatomic, assign) FUComicFilterStyle style;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
20
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUConfig.h
Executable file
20
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUConfig.h
Executable file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// FUConfig.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUParam.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUConfig : NSObject
|
||||
|
||||
- (int)setValue:(id)value forName:(NSString *)name paramType:(FUParamType)paramType;
|
||||
|
||||
- (id)getValueForName:(NSString *)name paramType:(FUParamType)paramType;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// FUCustomBackground.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by liuyang on 2022/1/7.
|
||||
//
|
||||
#import "FUBackground.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUCustomBackground : FUBackground
|
||||
|
||||
@property (nonatomic, strong) UIImage *image;
|
||||
|
||||
- (instancetype)initWithPath:(NSString *)path name:(NSString *)name image:(UIImage *)image;
|
||||
|
||||
+ (instancetype)backgroundWithPath:(NSString *)path name:(NSString *)name image:(UIImage *)image;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,123 @@
|
||||
//
|
||||
// FUDeformationKeys.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/12/23.
|
||||
//
|
||||
|
||||
#import "FUKeysDefine.h"
|
||||
|
||||
FUParamsKeysDefine(FUDeformation,
|
||||
//身材
|
||||
FUDeformationTall = @"tall", //高
|
||||
FUDeformationShort = @"short", //矮
|
||||
FUDeformationFat = @"fat", //胖
|
||||
FUDeformationThin = @"thin", //瘦
|
||||
|
||||
//脸型
|
||||
FUDeformationEyeNarrow = @"eye_narrow", //眼睛窄
|
||||
FUDeformationEyeWide = @"eye_wide", // 眼睛宽
|
||||
FUDeformationEyeDown = @"eye_down", //眼睛下
|
||||
FUDeformationEyeUp = @"eye_up", // 眼睛上
|
||||
FUDeformationEyeInner = @"eye_inner", // 眼睛内
|
||||
FUDeformationEyeBackward = @"eye_backward", //眼睛小
|
||||
FUDeformationEyeForward = @"eye_forward", //眼睛大
|
||||
FUDeformationUpperlidoutNarrow = @"upperLidOut_narrow", //外上眼皮右
|
||||
FUDeformationUpperlidoutWide = @"upperLidOut_wide", // 外上眼皮左
|
||||
FUDeformationUpperlidoutDown = @"upperLidOut_down", //外上眼皮左下
|
||||
FUDeformationUpperlidoutUp = @"upperLidOut_up", //外上眼皮左上
|
||||
FUDeformationUpperlidmidNarrow = @"upperLidMid_narrow", //中上眼皮右
|
||||
FUDeformationUpperlidmidWide = @"upperLidMid_wide", // 中上眼皮左
|
||||
FUDeformationUpperlidmidDown = @"upperLidMid_down", // 中上眼皮下
|
||||
FUDeformationUpperlidmidUp = @"upperLidMid_up", // 中上眼皮上
|
||||
FUDeformationUpperlidinNarrow = @"upperLidIn_narrow", //内上眼皮右
|
||||
FUDeformationUpperlidinWide = @"upperLidIn_wide", // 内上眼皮左
|
||||
FUDeformationUpperlidinDown = @"upperLidIn_down", //内上眼皮下
|
||||
FUDeformationUpperlidinUp = @"upperLidIn_up", // 内上眼皮上下
|
||||
FUDeformationLidinnerNarrow = @"lidInner_narrow", //内眼角内
|
||||
FUDeformationLidinnerWide = @"lidInner_wide", //内眼角外
|
||||
FUDeformationLidinnerDown = @"lidInner_down", //内眼角下
|
||||
FUDeformationLidinnerUp = @"lidInner_up", // 内眼角上
|
||||
FUDeformationLowerlidinNarrow = @"lowerLidIn_narrow", //内下眼皮右
|
||||
FUDeformationLowerlidinWide = @"lowerLidIn_wide", //内下眼皮左
|
||||
FUDeformationLowerlidinDown = @"lowerLidIn_down", // 内下眼皮下
|
||||
FUDeformationLowerlidinUp = @"lowerLidIn_up", //内下眼皮上
|
||||
FUDeformationLowerlidmidNarrow = @"lowerLidMid_narrow", //中下眼皮右
|
||||
FUDeformationLowerlidmidWide = @"lowerLidMid_wide", //中下眼皮左
|
||||
FUDeformationLowerlidmidDown = @"lowerLidMid_down", //中下眼皮下
|
||||
FUDeformationLowerlidmidUp = @"lowerLidMid_up", // 中下眼皮上
|
||||
FUDeformationLowerlidoutNarrow = @"lowerLidOut_narrow", // 外下眼皮右
|
||||
FUDeformationLowerlidoutWide = @"lowerLidOut_wide", //外下眼皮左
|
||||
FUDeformationLowerlidoutDown = @"lowerLidOut_down", // 外下眼皮下
|
||||
FUDeformationLowerlidoutUp = @"lowerLidOut_up", //外下眼皮上
|
||||
FUDeformationLidouterNarrow = @"lidOuter_narrow", //外眼角内
|
||||
FUDeformationLidouterWide = @"lidOuter_wide", // 外眼角外
|
||||
FUDeformationLidouterDown = @"lidOuter_down", //外眼角下
|
||||
FUDeformationLidouterUp = @"lidOuter_up", //外眼角上
|
||||
FUDeformationNoseDown = @"nose_down", //鼻子下
|
||||
FUDeformationNoseUp = @"nose_up", //鼻子上
|
||||
FUDeformationNoseBackward = @"nose_backward", //鼻子后
|
||||
FUDeformationNoseForward = @"nose_forward", //鼻子前
|
||||
FUDeformationNosetipDown = @"noseTip_down", // 鼻尖下
|
||||
FUDeformationNosetipUp = @"noseTip_up", //鼻尖上
|
||||
FUDeformationNosetipBackward = @"noseTip_backward", // 鼻尖后
|
||||
FUDeformationNosetipForward = @"noseTip_forward", // 鼻尖前
|
||||
FUDeformationUpperheadNarrow = @"upperHead_narrow", // 脸窄
|
||||
FUDeformationUpperheadWide = @"upperHead_wide", // 脸宽
|
||||
FUDeformationUpperheadDown = @"upperHead_down", // 上脸短
|
||||
FUDeformationUpperheadUp = @"upperHead_up", //上脸长
|
||||
FUDeformationUpperheadBackward = @"upperHead_backward", //上脸后
|
||||
FUDeformationUpperheadForward = @"upperHead_forward", //上脸前
|
||||
FUDeformationLowerheadDown = @"lowerHead_down", //下脸长
|
||||
FUDeformationLowerheadUp = @"lowerHead_up", //下脸短
|
||||
FUDeformationLowerheadBackward = @"lowerHead_backward", // 下脸后
|
||||
FUDeformationLowerheadForward = @"lowerHead_forward", //下脸前
|
||||
FUDeformationUpperjawNarrow = @"upperJaw_narrow", //脸颊瘦
|
||||
FUDeformationUpperjawWide = @"upperJaw_wide", //脸颊胖
|
||||
FUDeformationMidjawNarrow = @"midJaw_narrow", //下颚瘦
|
||||
FUDeformationMidjawWide = @"midJaw_wide", //下颚胖
|
||||
FUDeformationMidjawDown = @"midJaw_down", //下颚下
|
||||
FUDeformationMidjawUp = @"midJaw_up", //下颚上
|
||||
FUDeformationLowerjawNarrow = @"lowerJaw_narrow", //腮帮瘦
|
||||
FUDeformationLowerjawWide = @"lowerJaw_wide", //腮帮胖
|
||||
FUDeformationLowerjawDown = @"lowerJaw_down", //腮帮下
|
||||
FUDeformationLowerjawUp = @"lowerJaw_up", //腮帮上
|
||||
FUDeformationJawlineNarrow = @"jawLine_narrow", // 下颌角窄
|
||||
FUDeformationJawlineWide = @"jawLine_wide", // 下颌角宽
|
||||
FUDeformationJawlineDown = @"jawLine_down", // 下颌角下
|
||||
FUDeformationJawlineUp = @"jawLine_up", // 下颌角上
|
||||
FUDeformationJawtipNarrow = @"jawTip_narrow", // 下巴瘦
|
||||
FUDeformationJawtipWide = @"jawTip_wide", //下巴胖
|
||||
FUDeformationJawtipDown = @"jawTip_down", //下巴下
|
||||
FUDeformationJawtipUp = @"jawTip_up", // 下巴上
|
||||
FUDeformationJawtipBackward = @"jawTip_backward", //下巴后
|
||||
FUDeformationJawtipForward = @"jawTip_forward", //下巴前
|
||||
FUDeformationJawtipPeakNarrow = @"jawTip_peak_narrow", //下巴尖窄
|
||||
FUDeformationJawtipPeakWide = @"jawTip_peak_wide", // 下巴尖宽
|
||||
FUDeformationJawtipPeakDown = @"jawTip_peak_down", // 下巴尖长
|
||||
FUDeformationJawtipPeakUp = @"jawTip_peak_up", // 下巴尖短
|
||||
FUDeformationJawtipPeakBackward = @"jawTip_peak_backward", // 下巴尖后
|
||||
FUDeformationJawtipPeakForward = @"jawTip_peak_forward", //下巴尖前
|
||||
FUDeformationLowerchinDown = @"lowerChin_down", // 下巴内侧下
|
||||
FUDeformationLowerchinUp = @"lowerChin_up", //下巴内侧上
|
||||
FUDeformationMouthNarrow = @"mouth_narrow", // 嘴巴小
|
||||
FUDeformationMouthWide = @"mouth_wide", //嘴巴大
|
||||
FUDeformationMouthDown = @"mouth_down", //嘴巴下
|
||||
FUDeformationMouthUp = @"mouth_up", // 嘴巴上
|
||||
FUDeformationMouthBackward = @"mouth_backward", // 嘴巴后
|
||||
FUDeformationMouthForward = @"mouth_forward", // 嘴巴前
|
||||
FUDeformationGlobalbrowDown = @"globalBrow_down", // 眉毛下
|
||||
FUDeformationGlobalbrowUp = @"globalBrow_up", // 眉毛上
|
||||
FUDeformationInnerbrowDown = @"InnerBrow_down", //内眉毛下
|
||||
FUDeformationInnerbrowUp = @"InnerBrow_up", //内眉毛上
|
||||
FUDeformationMiddlebrowDown = @"middleBrow_down", // 中眉毛下
|
||||
FUDeformationMiddlebrowUp = @"middleBrow_up", // 中眉毛上
|
||||
FUDeformationOuterbrowDown = @"outerBrow_down", // 外眉毛下
|
||||
FUDeformationOuterbrowUp = @"outerBrow_up", //外眉毛上
|
||||
FUDeformationEarNarrow = @"ear_narrow", //耳朵小
|
||||
FUDeformationEarWide = @"ear_wide", //耳朵大
|
||||
FUDeformationEarDown = @"ear_down", //耳朵下
|
||||
FUDeformationEarUp = @"ear_up", //耳朵上
|
||||
FUDeformationUpperearDown = @"upperEar_down", // 上耳朵下
|
||||
FUDeformationUpperearUp = @"upperEar_up" // 上耳朵上
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// FUFaceRectInfo.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/26.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreGraphics/CGGeometry.h>
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUFaceRectInfo : NSObject
|
||||
+ (instancetype)faceWithId:(int)faceId rect:(CGRect)rect;
|
||||
|
||||
@property (nonatomic, assign) int faceId;
|
||||
@property (nonatomic, assign) CGRect rect;//人脸脸所在图片上的位置
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
112
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUFacepupKeys.h
Executable file
112
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUFacepupKeys.h
Executable file
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// FUFacepupKeys.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by ly-Mac on 2020/12/23.
|
||||
//
|
||||
#import "FUKeysDefine.h"
|
||||
|
||||
//FUParamsKeysDefine(FUFacepup,
|
||||
// // 脸型
|
||||
// FUFacepupHeadBoneWide = @"HeadBone_wide", // 头型变宽
|
||||
// FUFacepupHeadNarrow = @"Head_narrow", // 头型变窄
|
||||
// FUFacepupHeadShrink = @"head_shrink", // 头部缩短
|
||||
// FUFacepupHeadStretch = @"head_stretch", // 头部拉长
|
||||
// FUFacepupHeadFat = @"head_fat", // 胖
|
||||
// FUFacepupHeadThin = @"head_thin", // 瘦
|
||||
// FUFacepupCheekWide = @"cheek_wide", // 颊变宽
|
||||
// FUFacepupCheekBoneNarrow = @"cheekbone_narrow", // 颊变短
|
||||
// FUFacepupJawBoneWide = @"jawbone_Wide", // 下颌角向下
|
||||
// FUFacepupJawBoneNarrow = @"jawbone_Narrow", // 下颌角向下
|
||||
// FUFacepupJawMWide = @"jaw_m_wide", // 下颌变宽
|
||||
// FUFacepupJawMNarrow = @"jaw_M_narrow", // 下颌变窄
|
||||
// FUFacepupJawWide = @"jaw_wide", // 下巴变宽
|
||||
// FUFacepupJawNarrow = @"jaw_narrow", // 下巴变窄
|
||||
// FUFacepupJawUp = @"jaw_up", // 下巴变短
|
||||
// FUFacepupJawLower = @"jaw_lower", // 下巴变长
|
||||
// FUFacepupJawtipForward = @"jawTip_forward", // 下巴向前
|
||||
// FUFacepupJawtipBackward = @"jawTip_backward", // 下巴向后
|
||||
// FUFacepupJawboneMUp = @"jawBone_m_up", // 下颌中间变窄
|
||||
// FUFacepupJawboneMDown = @"jawBone_m_down", // 下颌中间变宽
|
||||
//
|
||||
// // 眼睛
|
||||
// FUFacepupEyeWide = @"Eye_wide", // 眼睛放大
|
||||
// FUFacepupEyeShrink = @"Eye_shrink", // 眼睛缩小
|
||||
// FUFacepupEyeUp = @"Eye_up", // 眼睛向上
|
||||
// FUFacepupEyeDown = @"Eye_down", // 眼睛向下
|
||||
// FUFacepupEyeIn = @"Eye_in", // 眼睛向里
|
||||
// FUFacepupEyeOut = @"Eye_out", // 眼睛向外
|
||||
// FUFacepupEyeCloseL = @"Eye_close_L", // 左眼闭
|
||||
// FUFacepupEyeCloseR = @"Eye_close_R", // 右眼闭
|
||||
// FUFacepupEyeOpenL = @"Eye_open_L", // 左眼睁
|
||||
// FUFacepupEyeOpenR = @"Eye_open_R", // 右眼睁
|
||||
// FUFacepupEyeUpperUpL = @"Eye_upper_up_L", // 左上眼皮向上
|
||||
// FUFacepupEyeUpperUpR = @"Eye_upper_up_R", // 右上眼皮向上
|
||||
// FUFacepupEyeUpperDownL = @"Eye_upper_down_L", // 左上眼皮向下
|
||||
// FUFacepupEyeUpperDownR = @"Eye_upper_down_R", // 右上眼皮向下
|
||||
// FUFacepupEyeUpperbendInL = @"Eye_upperBend_in_L", // 左上眼皮向里
|
||||
// FUFacepupEyeUpperbendInR = @"Eye_upperBend_in_R", // 右上眼皮向里
|
||||
// FUFacepupEyeUpperbendOutL = @"Eye_upperBend_out_L", // 左上眼皮向外
|
||||
// FUFacepupEyeUpperbendOutR = @"Eye_upperBend_out_R", // 右上眼皮向外
|
||||
// FUFacepupEyeDownerUpL = @"Eye_downer_up_L", // 左下眼皮向上
|
||||
// FUFacepupEyeDownerUpR = @"Eye_downer_up_R", // 右下眼皮向上
|
||||
// FUFacepupEyeDownerDnL = @"Eye_downer_dn_L", // 左下眼皮向下
|
||||
// FUFacepupEyeDownerDnR = @"Eye_downer_dn_R", // 右下眼皮向下
|
||||
// FUFacepupEyeDownerbendInL = @"Eye_downerBend_in_L", // 左下眼皮向里
|
||||
// FUFacepupEyeDownerbendInR = @"Eye_downerBend_in_R", // 右下眼皮向里
|
||||
// FUFacepupEyeDownerbendOutL = @"Eye_downerBend_out_L", // 左下眼皮向外
|
||||
// FUFacepupEyeDownerbendOutR = @"Eye_downerBend_out_R", // 右下眼皮向外
|
||||
// FUFacepupEyeOutterIn = @"Eye_outter_in", // 外眼角向里
|
||||
// FUFacepupEyeOutterOut = @"Eye_outter_out", // 外眼角向外
|
||||
// FUFacepupEyeOutterUp = @"Eye_outter_up", // 外眼角向上
|
||||
// FUFacepupEyeOutterDown = @"Eye_outter_down", // 外眼角向下
|
||||
// FUFacepupEyeInnerIn = @"Eye_inner_in", // 内眼角向里
|
||||
// FUFacepupEyeInnerOut = @"Eye_inner_out", // 内眼角向外
|
||||
// FUFacepupEyeInnerUp = @"Eye_inner_up", // 内眼角向上
|
||||
// FUFacepupEyeInnerDown = @"Eye_inner_down", // 内眼角向下
|
||||
// FUFacepupEyeForward = @"Eye_forward", // 眼睛向前
|
||||
//
|
||||
// // 嘴巴
|
||||
// FUFacepupUpperlipThick = @"upperLip_Thick", // 上唇变厚
|
||||
// FUFacepupUpperlipsideThick = @"upperLipSide_Thick", // 上唇两侧变厚
|
||||
// FUFacepupLowerlipThick = @"lowerLip_Thick", // 下唇变厚
|
||||
// FUFacepupLowerlipsideThin = @"lowerLipSide_Thin", // 下唇两侧变薄
|
||||
// FUFacepupLowerlipsideThick = @"lowerLipSide_Thick", // 下唇两侧变厚
|
||||
// FUFacepupUpperlipThin = @"upperLip_Thin", // 上唇变薄
|
||||
// FUFacepupLowerlipThin = @"lowerLip_Thin", // 下唇变薄
|
||||
// FUFacepupMouthMagnify = @"mouth_magnify", // 嘴巴放大
|
||||
// FUFacepupMouthShrink = @"mouth_shrink", // 嘴巴缩小
|
||||
// FUFacepupLipcornerOut = @"lipCorner_Out", // 嘴角向外
|
||||
// FUFacepupLipcornerIn = @"lipCorner_In", // 嘴角向里
|
||||
// FUFacepupLipcornerUp = @"lipCorner_up", // 嘴角向上
|
||||
// FUFacepupLipcornerDown = @"lipCorner_down", // 嘴角向下
|
||||
// FUFacepupMouthMDown = @"mouth_m_down", // 唇尖向下
|
||||
// FUFacepupMouthMUp = @"mouth_m_up", // 唇尖向上
|
||||
// FUFacepupMouthUp = @"mouth_Up", // 嘴向上
|
||||
// FUFacepupMouthDown = @"mouth_Down", // 嘴向下
|
||||
// FUFacepupMouthSideUp = @"mouth_side_up", // 唇线两侧向上
|
||||
// FUFacepupMouthSideDown = @"mouth_side_down", // 唇线两侧向下
|
||||
// FUFacepupMouthForward = @"mouth_forward", // 嘴向前
|
||||
// FUFacepupMouthBackward = @"mouth_backward", // 嘴向后
|
||||
// FUFacepupUpperlipsideThin = @"upperLipSide_thin", // 上唇两侧变薄
|
||||
//
|
||||
// // 鼻子
|
||||
// FUFacepupNostrilOut = @"nostril_Out", // 鼻翼变宽
|
||||
// FUFacepupNostrilIn = @"nostril_In", // 鼻翼变窄
|
||||
// FUFacepupNosetipUp = @"noseTip_Up", // 鼻尖向上
|
||||
// FUFacepupNosetipDown = @"noseTip_Down", // 鼻尖向下
|
||||
// FUFacepupNoseUp = @"nose_Up", // 鼻子向上
|
||||
// FUFacepupNoseTall = @"nose_tall", // 鼻子变高
|
||||
// FUFacepupNoseLow = @"nose_low", // 鼻子变矮
|
||||
// FUFacepupNoseDown = @"nose_Down", // 鼻子向下
|
||||
// FUFacepupNosetipForward = @"noseTip_forward", // 鼻尖向前
|
||||
// FUFacepupNosetipBackward = @"noseTip_backward", // 鼻尖向后
|
||||
// FUFacepupNosetipMagnify = @"noseTip_magnify", // 鼻尖放大
|
||||
// FUFacepupNosetipShrink = @"noseTip_shrink", // 鼻尖缩小
|
||||
// FUFacepupNostrilUp = @"nostril_up", // 鼻翼向上
|
||||
// FUFacepupNostrilDown = @"nostril_down", // 鼻翼向下
|
||||
// FUFacepupNoseboneTall = @"noseBone_tall", // 鼻梁变高
|
||||
// FUFacepupNoseboneLow = @"noseBone_low", // 鼻梁变低
|
||||
// FUFacepupNoseWide = @"nose_wide", // 鼻子变宽
|
||||
// FUFacepupNoseShrink = @"nose_shrink" // 鼻子变窄
|
||||
// )
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// FUFacialFeatures.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/3/19.
|
||||
//
|
||||
|
||||
#import "FUSticker.h"
|
||||
#import "CNamaSDK.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
/**
|
||||
* 面部特征
|
||||
*/
|
||||
@interface FUFacialFeatures : FUSticker
|
||||
@property (nonatomic, assign) FUAITYPE aiType;
|
||||
|
||||
@property (nonatomic, assign) FUAITYPE landmarksType;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// FUFilterDefineKey.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by Chen on 2021/1/5.
|
||||
//
|
||||
|
||||
#ifndef FUFilterDefineKey_h
|
||||
#define FUFilterDefineKey_h
|
||||
|
||||
#import "FUKeysDefine.h"
|
||||
|
||||
FUParamsKeysDefine(FUFilter,
|
||||
|
||||
FUFilterOrigin = @"origin",
|
||||
|
||||
//自然
|
||||
FUFilterZiRan1 = @"ziran1",
|
||||
FUFilterZiRan2 = @"ziran2",
|
||||
FUFilterZiRan3 = @"ziran3",
|
||||
FUFilterZiRan4 = @"ziran4",
|
||||
FUFilterZiRan5 = @"ziran5",
|
||||
FUFilterZiRan6 = @"ziran6",
|
||||
FUFilterZiRan7 = @"ziran7",
|
||||
FUFilterZiRan8 = @"ziran8",
|
||||
|
||||
//质感灰
|
||||
FUFilterZhiGanHui1 = @"zhiganhui1",
|
||||
FUFilterZhiGanHui2 = @"zhiganhui2",
|
||||
FUFilterZhiGanHui3 = @"zhiganhui3",
|
||||
FUFilterZhiGanHui4 = @"zhiganhui4",
|
||||
FUFilterZhiGanHui5 = @"zhiganhui5",
|
||||
FUFilterZhiGanHui6 = @"zhiganhui6",
|
||||
FUFilterZhiGanHui7 = @"zhiganhui7",
|
||||
FUFilterZhiGanHui8 = @"zhiganhui8",
|
||||
|
||||
//蜜桃
|
||||
FUFilterMiTao1 = @"mitao1",
|
||||
FUFilterMiTao2 = @"mitao2",
|
||||
FUFilterMiTao3 = @"mitao3",
|
||||
FUFilterMiTao4 = @"mitao4",
|
||||
FUFilterMiTao5 = @"mitao5",
|
||||
FUFilterMiTao6 = @"mitao6",
|
||||
FUFilterMiTao7 = @"mitao7",
|
||||
FUFilterMiTao8 = @"mitao8",
|
||||
|
||||
//白亮
|
||||
FUFilterBaiLiang1 = @"bailiang1",
|
||||
FUFilterBaiLiang2 = @"bailiang2",
|
||||
FUFilterBaiLiang3 = @"bailiang3",
|
||||
FUFilterBaiLiang4 = @"bailiang4",
|
||||
FUFilterBaiLiang5 = @"bailiang5",
|
||||
FUFilterBaiLiang6 = @"bailiang6",
|
||||
FUFilterBaiLiang7 = @"bailiang7",
|
||||
|
||||
//粉嫩
|
||||
FUFilterFenNen1 = @"fennen1",
|
||||
FUFilterFenNen2 = @"fennen2",
|
||||
FUFilterFenNen3 = @"fennen3",
|
||||
FUFilterFenNen4 = @"fennen4",
|
||||
FUFilterFenNen5 = @"fennen5",
|
||||
FUFilterFenNen6 = @"fennen6",
|
||||
FUFilterFenNen7 = @"fennen7",
|
||||
FUFilterFenNen8 = @"fennen8",
|
||||
|
||||
//冷色调
|
||||
FUFilterLengSeDiao1 = @"lengsediao1",
|
||||
FUFilterLengSeDiao2 = @"lengsediao2",
|
||||
FUFilterLengSeDiao3 = @"lengsediao3",
|
||||
FUFilterLengSeDiao4 = @"lengsediao4",
|
||||
FUFilterLengSeDiao5 = @"lengsediao5",
|
||||
FUFilterLengSeDiao6 = @"lengsediao6",
|
||||
FUFilterLengSeDiao7 = @"lengsediao7",
|
||||
FUFilterLengSeDiao8 = @"lengsediao8",
|
||||
FUFilterLengSeDiao11 = @"lengsediao11",
|
||||
|
||||
//暖色调
|
||||
FUFilterNuanSeDiao1 = @"nuansediao1",
|
||||
FUFilterNuanSeDiao2 = @"nuansediao2",
|
||||
|
||||
//个性
|
||||
FUFilterGeXing1 = @"gexing1",
|
||||
FUFilterGeXing2 = @"gexing2",
|
||||
FUFilterGeXing3 = @"gexing3",
|
||||
FUFilterGeXing4 = @"gexing4",
|
||||
FUFilterGeXing5 = @"gexing5",
|
||||
FUFilterGeXing6 = @"gexing6",
|
||||
FUFilterGeXing7 = @"gexing7",
|
||||
FUFilterGeXing10 = @"gexing10",
|
||||
FUFilterGeXing11 = @"gexing11",
|
||||
|
||||
//小清新
|
||||
FUFilterXiaoQingXin1 = @"xiaoqingxin1",
|
||||
FUFilterXiaoQingXin3 = @"xiaoqingxin3",
|
||||
FUFilterXiaoQingXin4 = @"xiaoqingxin4",
|
||||
FUFilterXiaoQingXin6 = @"xiaoqingxin6",
|
||||
|
||||
//黑白
|
||||
FUFilterHeiBai1 = @"heibai1",
|
||||
FUFilterHeiBai2 = @"heibai2",
|
||||
FUFilterHeiBai3 = @"heibai3",
|
||||
FUFilterHeiBai4 = @"heibai4"
|
||||
)
|
||||
#endif /* FUFilterDefineKey_h */
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// FUGLContext.h
|
||||
// FUStaLiteDemo
|
||||
//
|
||||
// Created by ly-Mac on 2019/8/9.
|
||||
// Copyright © 2019 ly-Mac. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <OpenGLES/EAGL.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol FUGLContextProtocol <NSObject>
|
||||
|
||||
@required
|
||||
- (void)glQueueAsync:(dispatch_block_t)block;
|
||||
|
||||
- (void)glQueueSync:(dispatch_block_t)block;
|
||||
|
||||
- (void)glContextDidChange;
|
||||
|
||||
@property (nonatomic, weak) EAGLContext *currentGLContext;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUGLContext : NSObject
|
||||
|
||||
@property (nonatomic,strong, readonly) EAGLContext *currentGLContext;
|
||||
|
||||
+ (instancetype)shareGLContext;
|
||||
|
||||
- (void)setCustomGLContext:(EAGLContext *)customGLContext;
|
||||
|
||||
- (void)glQueueAsync:(dispatch_block_t)block;
|
||||
|
||||
- (void)glQueueSync:(dispatch_block_t)block;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// FUSceneView.h
|
||||
// FULiveDemo
|
||||
//
|
||||
// Created by 刘洋 on 2017/8/15.
|
||||
// Copyright © 2017年 刘洋. All rights reserved.
|
||||
//
|
||||
|
||||
#import <GLKit/GLKit.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, FUGLDisplayViewOrientation) {
|
||||
FUGLDisplayViewOrientationPortrait = 0,
|
||||
FUGLDisplayViewOrientationLandscapeRight = 1,
|
||||
FUGLDisplayViewOrientationPortraitUpsideDown = 2,
|
||||
FUGLDisplayViewOrientationLandscapeLeft = 3,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, FUGLDisplayViewContentMode) {
|
||||
/* 等比例短边充满 */
|
||||
FUGLDisplayViewContentModeScaleAspectFill = 0,
|
||||
/* 拉伸铺满 */
|
||||
FUGLDisplayViewContentModeScaleToFill = 1,
|
||||
/* 等比例长边充满 */
|
||||
FUGLDisplayViewContentModeScaleAspectFit = 2,
|
||||
|
||||
};
|
||||
|
||||
@class FUGLDisplayView;
|
||||
@protocol FUGLDisplayViewGestureDelegate <NSObject>
|
||||
|
||||
- (void)displayView:(FUGLDisplayView *)displayView panMovedWithTranslation:(CGPoint)translation translationDelta:(CGPoint)translationDelta gestureState:(UIGestureRecognizerState)gestureState;
|
||||
|
||||
- (void)displayView:(FUGLDisplayView *)displayView pinchMovedWithScale:(CGFloat)scale scaleDelta:(CGFloat)scaleDelta gestureState:(UIGestureRecognizerState)gestureState;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUGLDisplayView : UIView
|
||||
|
||||
@property (nonatomic, assign) FUGLDisplayViewContentMode contentMode;
|
||||
// 设置视频朝向,保证视频总是竖屏播放
|
||||
@property (nonatomic, assign) FUGLDisplayViewOrientation orientation;
|
||||
|
||||
@property (nonatomic, weak) id<FUGLDisplayViewGestureDelegate> gestureDelegate;
|
||||
|
||||
@property (nonatomic, assign) NSInteger disapplePointIndex;
|
||||
|
||||
@property (nonatomic, assign) BOOL alphaEnable;
|
||||
|
||||
- (void)setDisplayFramebuffer;
|
||||
- (void)displayPixelBuffer:(CVPixelBufferRef)pixelBuffer;
|
||||
- (void)displayImageData:(void *)imageData withSize:(CGSize)size;
|
||||
|
||||
- (void)displayPixelBuffer:(CVPixelBufferRef)pixelBuffer withLandmarks:(float *)landmarks count:(int)count;
|
||||
- (void)presentFramebuffer;
|
||||
|
||||
- (void)displayTexture:(int)texture withTextureSize:(CGSize)textureSize;
|
||||
|
||||
/// 点位取色
|
||||
/// @param point glView上的点坐标
|
||||
- (UIColor *)colorInPoint:(CGPoint)point;
|
||||
|
||||
@end
|
||||
20
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUGesture.h
Executable file
20
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUGesture.h
Executable file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// FUGestureItem.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/28.
|
||||
//
|
||||
|
||||
#import "FUSticker.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* 手势道具
|
||||
*/
|
||||
@interface FUGesture : FUSticker
|
||||
//比心道具支持自动调整y轴位置
|
||||
@property (nonatomic, assign) double handOffY;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// FUGreenTent.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/15.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
#import "FUStruct.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@interface FUGreenScreen : FUItem
|
||||
|
||||
/// 背景图片
|
||||
@property (nonatomic, strong, nullable) UIImage *backgroundImage;
|
||||
|
||||
/// 背景视频URLString
|
||||
/// @note 设置之后自动开始播放,若设置为nil,自动停止
|
||||
@property (nonatomic, copy, nullable) NSString *videoPath;
|
||||
|
||||
/// 安全区域图片
|
||||
@property (nonatomic, strong, nullable) UIImage *safeAreaImage;
|
||||
|
||||
/// 关键颜色
|
||||
/// 默认值为[0,255,0],取值范围[0-255,0-255,0-255]
|
||||
/// @note 设置关键颜色后会自动改变相似度、平滑度和祛色度的值
|
||||
@property (nonatomic, assign) FUColor keyColor;
|
||||
|
||||
/// 相似度:色度最大容差
|
||||
/// 取值范围0.0-1.0,色度最大,容差值越大,更多幕景被抠除
|
||||
/// @note 值跟随关键颜色变化
|
||||
@property (nonatomic, assign) double chromaThres;
|
||||
|
||||
/// 平滑度:色度最小限差,
|
||||
/// 取值范围0.0-1.0,值越大,更多幕景被扣除
|
||||
/// @note 值跟随关键颜色变化
|
||||
@property (nonatomic, assign) double chromaThrest;
|
||||
|
||||
/// 祛色度:图像前后景祛色度过度
|
||||
/// 取值范围0.0-1.0,值越大,两者边缘处透明过度更平滑
|
||||
/// @note 值跟随关键颜色变化
|
||||
@property (nonatomic, assign) double alphal;
|
||||
|
||||
/// 中心点
|
||||
@property (nonatomic, assign) CGPoint center;
|
||||
|
||||
/// 缩放比例
|
||||
@property (nonatomic, assign) float scale;
|
||||
|
||||
/// 当前是否正在进行抠图,抠图就停止绿慕渲染
|
||||
@property (nonatomic, assign) BOOL cutouting;
|
||||
|
||||
/// 背景视频播放是否暂停
|
||||
@property (nonatomic, assign) BOOL pause;
|
||||
|
||||
/// 开始播放背景视频
|
||||
- (void)startVideoDecode;
|
||||
|
||||
/// 取消播放背景视频
|
||||
- (void)stopVideoDecode;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// FUGroupAnimation.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by liuyang on 2021/4/22.
|
||||
//
|
||||
|
||||
#import "FUAnimation.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUGroupAnimation : FUAnimation
|
||||
|
||||
@property (nonatomic, copy, readonly) NSArray<FUItem *> *components;
|
||||
|
||||
@property (nonatomic, copy, readonly) NSArray<FUAnimation *> *componentAnimations;
|
||||
|
||||
- (instancetype)initWithPath:(NSString *)path name:(nullable NSString *)name components:(nullable NSArray<FUItem *> *)components componentAnimations:(nullable NSArray<FUAnimation *> *)componentAnimations;
|
||||
+ (instancetype)groupAnimationWithPath:(NSString *)path name:(nullable NSString *)name components:(nullable NSArray<FUItem *> *)components componentAnimations:(nullable NSArray<FUAnimation *> *)componentAnimations;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// FUHairItem.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/15.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
#import "FUStruct.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUHairBeauty : FUItem
|
||||
/**
|
||||
* 单色美发道具 index 对应的值范围 0 - 7,渐变色美发道具,index对应的值范围 0 - 4
|
||||
*/
|
||||
@property (nonatomic, assign) int index;
|
||||
/**
|
||||
* 0对应无效果,1对应最强效果,中间连续过渡。
|
||||
*/
|
||||
@property (nonatomic, assign) double strength;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUHairBeauty (normal)
|
||||
@property (nonatomic, assign) FULABColor normalColor;
|
||||
@property (nonatomic, assign) double shine;
|
||||
@end
|
||||
|
||||
|
||||
@interface FUHairBeauty (gradient)
|
||||
@property (nonatomic, assign) FULABColor gradientColor0;
|
||||
@property (nonatomic, assign) FULABColor gradientColor1;
|
||||
|
||||
@property (nonatomic, assign) double shine0;
|
||||
@property (nonatomic, assign) double shine1;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// FUHairDefineKey.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by Chen on 2021/1/20.
|
||||
//
|
||||
|
||||
#ifndef FUHairDefineKey_h
|
||||
#define FUHairDefineKey_h
|
||||
|
||||
#import "FUKeysDefine.h"
|
||||
|
||||
FUParamsKeysDefine(FUHairColor,
|
||||
|
||||
FUHairColorL = @"Col_L",
|
||||
FUHairColorA = @"Col_A",
|
||||
FUHairColorB = @"Col_B",
|
||||
|
||||
FUHairColor0L = @"Col0_L",
|
||||
FUHairColor0A = @"Col0_A",
|
||||
FUHairColor0B = @"Col0_B",
|
||||
|
||||
FUHairColor1L = @"Col1_L",
|
||||
FUHairColor1A = @"Col1_A",
|
||||
FUHairColor1B = @"Col1_B",
|
||||
)
|
||||
|
||||
#endif /* FUHairDefineKey_h */
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// FUImageHelper.h
|
||||
// FULiveDemo
|
||||
//
|
||||
// Created by L on 2018/8/3.
|
||||
// Copyright © 2018年 L. All rights reserved.
|
||||
//
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface FUImageHelper : NSObject
|
||||
|
||||
+ (void)convertUIImageToBitmapRGBA8:(UIImage *)image completionHandler:(void (^)(int32_t size, unsigned char * bits))completionHandler;
|
||||
|
||||
+ (UIImage *)convertBitmapRGBA8ToUIImage:(unsigned char *)buffer
|
||||
withWidth:(int)width
|
||||
withHeight:(int)height;
|
||||
|
||||
/// 根据UIImage返回CVPixelBufferRef
|
||||
/// @param image UIImage实例对象
|
||||
/// 注意:CVPixelBufferRef需要手动release
|
||||
+ (CVPixelBufferRef)pixelBufferFromImage:(UIImage *)image;
|
||||
|
||||
/// 根据CVPixelBufferRef返回UIImage
|
||||
/// @param pixelBufferRef buffer
|
||||
/// 注意:如果后续业务有使用到image.CGImage,则需要及时释放掉 image.CGImage
|
||||
+ (UIImage *)imageFromPixelBuffer:(CVPixelBufferRef)pixelBufferRef;
|
||||
|
||||
+ (unsigned char *)getRGBAWithImage:(UIImage *)image;
|
||||
|
||||
+ (unsigned char *)getRGBAWithImageName:(NSString *)imageName width:(int *)width height:(int *)height;
|
||||
|
||||
/// 截屏处理取色
|
||||
+ (UIColor*)getPixelColorScreenWindowAtLocation:(CGPoint)point;
|
||||
|
||||
/// 针对静态图片处理取色
|
||||
+ (UIColor *)getPixelColorWithImage:(UIImage *)image point:(CGPoint)point DEPRECATED_MSG_ATTRIBUTE("use colorInPoint: in FUGLDisplayView instead");
|
||||
|
||||
/// 针对每一帧处理取色
|
||||
+ (UIColor *)getPixelColorWithPixelBuff:(CVPixelBufferRef)pixelBuffer point:(CGPoint)point DEPRECATED_MSG_ATTRIBUTE("use colorInPoint: in FUGLDisplayView instead");
|
||||
|
||||
+ (UIImage *)rotateImageWithAngle:(UIImage*)vImg Angle:(NSInteger)vAngle IsExpand:(BOOL)vIsExpand;
|
||||
|
||||
/// 获取图像数据
|
||||
/// @param pixelBuffer buffer
|
||||
/// @param transform 图像方向(0: up 1: right 2: down 3: left)
|
||||
/// @return Byte
|
||||
+ (Byte *)getBytesFromPixelBuffer:(CVPixelBufferRef)pixelBuffer transform:(int)transform;
|
||||
|
||||
/// 获取视频第一帧图片
|
||||
/// @param videoURL 视频URL
|
||||
+ (UIImage *)getPreviewImageWithVideoURL:(NSURL *)videoURL;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// FUInternalCameraSetting.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by ly-Mac on 2021/3/2.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@interface FUInternalCameraSetting : NSObject
|
||||
|
||||
/// 相机采集格式
|
||||
/// 默认为kCVPixelFormatType_32BGRA
|
||||
@property (nonatomic, assign) int format;
|
||||
|
||||
/// 相机分辨率
|
||||
/// 默认为AVCaptureSessionPreset1280x720
|
||||
@property (nonatomic, copy) AVCaptureSessionPreset sessionPreset;
|
||||
|
||||
/// 相机前后置摄像头
|
||||
/// 默认为AVCaptureDevicePositionFront
|
||||
@property (nonatomic, assign) AVCaptureDevicePosition position;
|
||||
|
||||
/// 默认为30
|
||||
@property (nonatomic, assign) int fps;
|
||||
|
||||
/// 是否打开内部虚拟相机
|
||||
/// 需要注意的是,在打开内部虚拟相机时,用户如果使用Scene相关需要真实相机的功能,内部会自动开启真实相机
|
||||
/// 并且当用户关闭相关Scene功能时,内部会自动关闭
|
||||
/// 默认为 NO
|
||||
@property (nonatomic, assign) BOOL useVirtualCamera; //
|
||||
|
||||
/// 如果使用内部相机时,SDK会自动判断当前是否需要使用系统相机,如果不需相机,内部会模拟一个相机并循环输出图像。
|
||||
/// 该属性可以设置输出图像的宽高,默认宽高为:720x1280,如果设置为CGSizeZero,则会使用 sessionPreset 的宽高。
|
||||
@property (nonatomic, assign) CGSize virtualCameraResolution;
|
||||
|
||||
/// 相机是否需要音频,默认为NO
|
||||
@property (nonatomic, assign) BOOL needsAudioTrack;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// FUItem+createTexture.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/8.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUItem (createTexture)
|
||||
|
||||
- (int)createTextureWithImage:(UIImage *)image forName:(NSString *)name;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
71
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUItem.h
Executable file
71
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUItem.h
Executable file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// FUItem.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/16.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUParam.h"
|
||||
#import "FURenderableObject.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUItem : FURenderableObject
|
||||
|
||||
@property (nonatomic, copy) NSString *name; // 道具名称
|
||||
|
||||
@property (nonatomic, copy) NSString *path; // 道具绝对路径
|
||||
|
||||
@property (nonatomic, copy, readonly) NSString *fileId;
|
||||
|
||||
@property (nonatomic, assign) BOOL supportARMode; // 是否支持 AR 模式
|
||||
|
||||
@property (nonatomic, copy) NSSet<NSNumber *> *bodyInvisibleList; // 身体隐藏区域
|
||||
|
||||
/// 根据道具路径创建道具对象,可支持自动加载
|
||||
/// @param path 道具路径
|
||||
/// @param name 道具名称
|
||||
/// @param fileId itemList 中的 path
|
||||
- (instancetype)initWithPath:(NSString *)path name:(nullable NSString *)name fileId:(nullable NSString *)fileId;
|
||||
|
||||
/// 根据道具路径创建道具对象,可支持自动加载
|
||||
/// @param path 道具路径
|
||||
/// @param name 道具名称
|
||||
- (instancetype)initWithPath:(NSString *)path name:(nullable NSString *)name;
|
||||
|
||||
+ (instancetype)itemWithPath:(NSString *)path name:(nullable NSString *)name fileId:(nullable NSString *)fileId;
|
||||
|
||||
+ (instancetype)itemWithPath:(NSString *)path name:(nullable NSString *)name;
|
||||
|
||||
- (int)setParam:(FUParam *)param;
|
||||
|
||||
- (int)setParam:(id)param forName:(NSString *)name paramType:(FUParamType)paramType;
|
||||
|
||||
- (id)getParamForName:(NSString *)name paramType:(FUParamType)paramType;
|
||||
|
||||
//把缓存的属性值全部设置一边
|
||||
- (BOOL)setAllProperty;
|
||||
|
||||
////replaceObj 被替换的对象
|
||||
//- (BOOL)replaceOldObj:(FUItem *)replaceObj;
|
||||
|
||||
////replaceOldBeauty 过滤不替换的属性名称
|
||||
//@property (nonatomic, copy) NSArray *(^FiltersBlock)(void);
|
||||
//
|
||||
///**
|
||||
// * 遇到结构体属性上抛给特定的FUItem处理,如 FUMakeup,FUHairItem*
|
||||
// * typeName属性类型,name 属性名称
|
||||
// */
|
||||
//@property (nonatomic, copy) void (^StructBlock)(NSString *typeName, NSString *name);
|
||||
//
|
||||
///**
|
||||
// * 遇到资源类的item上抛给特定的FUItem处理,如FUMakeup
|
||||
// * oldItem 属性类的item,如果是资源类,上层处理。否则就递归处理非资源类FUItem
|
||||
// * name 属性名称
|
||||
// */
|
||||
//@property (nonatomic, copy) void (^ResourceBlock)(FUItem *oldItem, NSString *name);
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// FUKeysDefine.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/12/22.
|
||||
//
|
||||
#import "metamacros.h"
|
||||
|
||||
#define FUParamsKeysDefine(keyPreName,...) \
|
||||
typedef NSString * keyPreName NS_STRING_ENUM; \
|
||||
metamacro_foreach_cxt(params_key_define,,static keyPreName , __VA_ARGS__) \
|
||||
static NSString *_##keyPreName##_constants_string = @"" #__VA_ARGS__; \
|
||||
_FUParamsKeys_GenerateImplementation(keyPreName)
|
||||
|
||||
#define params_key_define(INDEX, CONTEXT, VAR) CONTEXT const VAR;
|
||||
|
||||
#define _FUParamsKeys_GenerateImplementation(keyPreName) \
|
||||
static inline NSArray * keyPreName##AllKeys(){ \
|
||||
static NSArray *_##keyPreName##AllKeys = NULL; \
|
||||
static dispatch_once_t onceToken; \
|
||||
dispatch_once(&onceToken, ^{ \
|
||||
NSString *constantsString = _##keyPreName##_constants_string; \
|
||||
constantsString = [[constantsString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:@""]; \
|
||||
if ([constantsString hasSuffix:@","]) { \
|
||||
constantsString = [constantsString substringToIndex:[constantsString length]-1]; \
|
||||
} \
|
||||
NSArray *stringPairs = [constantsString componentsSeparatedByString:@","]; \
|
||||
NSMutableArray *keys = [NSMutableArray arrayWithCapacity:[stringPairs count]]; \
|
||||
for (NSString *stringPair in stringPairs) { \
|
||||
NSArray *labelAndValueString = [stringPair componentsSeparatedByString:@"="]; \
|
||||
NSString *key = [labelAndValueString objectAtIndex:1]; \
|
||||
key = [key stringByReplacingOccurrencesOfString:@"@\"" withString:@""]; \
|
||||
key = [key stringByReplacingOccurrencesOfString:@"\"" withString:@""]; \
|
||||
[keys addObject:key]; \
|
||||
} \
|
||||
_##keyPreName##AllKeys = [keys copy]; \
|
||||
}); \
|
||||
return _##keyPreName##AllKeys; \
|
||||
}
|
||||
16
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FULight.h
Executable file
16
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FULight.h
Executable file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// FULight.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/16.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FULight : FUItem
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// FULightMakeUpTextureKeyDefineKey.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by Chen on 2021/1/14.
|
||||
//
|
||||
|
||||
#ifndef FULightMakeUpTextureKeyDefineKey_h
|
||||
#define FULightMakeUpTextureKeyDefineKey_h
|
||||
|
||||
#import "FUKeysDefine.h"
|
||||
|
||||
FUParamsKeysDefine(FULightMakeUpTextureKey,
|
||||
//眉毛
|
||||
FULightMakeUpTextureKeyTexBrow = @"tex_brow",
|
||||
//眼影
|
||||
FULightMakeUpTextureKeyTexEye = @"tex_eye",
|
||||
//美瞳
|
||||
FULightMakeUpTextureKeyTexPupil = @"tex_pupil",
|
||||
//睫毛
|
||||
FULightMakeUpTextureKeyTexEyeLash = @"tex_eyeLash",
|
||||
//口红高光
|
||||
FULightMakeUpTextureKeyTexHighlight = @"tex_highlight",
|
||||
//眼线
|
||||
FULightMakeUpTextureKeyTexEyeLiner = @"tex_eyeLiner",
|
||||
//腮红
|
||||
FULightMakeUpTextureKeyTexBlusher = @"tex_blusher"
|
||||
)
|
||||
#endif /* FULightMakeUpTextureKeyDefineKey_h */
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// FULightMakeup.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/14.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
#import "FUStruct.h"
|
||||
#import <UIKit/UIImage.h>
|
||||
#import "FUMakeupValueDefine.h"
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FULightMakeup : FUItem
|
||||
@property (nonatomic, assign) BOOL isMakeupOn; //0 关 1开
|
||||
@property (nonatomic, assign) FUMakeupLipType lipType;//口红类型 0雾面 2润泽Ⅰ 3珠光 6高性能(不支持双色)7润泽Ⅱ
|
||||
@property (nonatomic, assign) BOOL isTwoColor;//口红双色开关,0为关闭,1为开启,如果想使用咬唇,开启双色开关,并且将makeup_lip_color2的值都设置为0
|
||||
@property (nonatomic, assign) BOOL makeupLipMask;//嘴唇优化效果开关,1.0为开 0为关
|
||||
@end
|
||||
@interface FULightMakeup (image)
|
||||
@property (nonatomic, strong) UIImage *subEyebrowImage;//眉毛
|
||||
@property (nonatomic, strong) UIImage *subEyeshadowImage;//眼影
|
||||
@property (nonatomic, strong) UIImage *subPupilImage;//美瞳
|
||||
@property (nonatomic, strong) UIImage *subEyelashImage;//睫毛
|
||||
@property (nonatomic, strong) UIImage *subHightLightImage;//高光
|
||||
@property (nonatomic, strong) UIImage *subEyelinerImage;//眼线
|
||||
@property (nonatomic, strong) UIImage *subBlusherImage;//腮红
|
||||
@end
|
||||
|
||||
@interface FULightMakeup (intensity)
|
||||
@property (nonatomic, assign) double intensityLip;//口红
|
||||
@property (nonatomic, assign) double intensityBlusher;//腮红
|
||||
@property (nonatomic, assign) double intensityEyeshadow;//眼影
|
||||
@property (nonatomic, assign) double intensityEyeliner;//眼线
|
||||
@property (nonatomic, assign) double intensityEyelash;//睫毛
|
||||
@property (nonatomic, assign) double intensityPupil;//美瞳
|
||||
@property (nonatomic, assign) double intensityEyebrow;//眉毛
|
||||
@end
|
||||
|
||||
@interface FULightMakeup (Color)
|
||||
@property (nonatomic, assign) FUColor makeUpLipColor;//口红颜色
|
||||
@end
|
||||
|
||||
@interface FULightMakeup (landMark)
|
||||
@property (nonatomic, assign) int isUserFix; //这个参数控制是否使用修改过得landmark点,如果设为1为使用,0为不使用
|
||||
@property (nonatomic, assign) FULandMark fixMakeUpData;//这个参数为一个数组,需要客户端传递一个数组进去,传递的数组的长度为 150*人脸数,也就是将所有的点位信息存储的数组中传递进来。
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// FUMakeUpChildStrengthKeyKey.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by Chen on 2021/1/6.
|
||||
//
|
||||
|
||||
#ifndef FUMakeUpChildStrengthKey_h
|
||||
#define FUMakeUpChildStrengthKey_h
|
||||
|
||||
#import "FUKeysDefine.h"
|
||||
|
||||
FUParamsKeysDefine(FUMakeUpChildStrengthKey,
|
||||
|
||||
//粉底
|
||||
FUMakeUpChildStrengthKeyIntensityFoundation = @"makeup_intensity_foundation",
|
||||
|
||||
//口红
|
||||
FUMakeUpChildStrengthKeyIntensityLip = @"makeup_intensity_lip",
|
||||
|
||||
//腮红
|
||||
FUMakeUpChildStrengthKeyIntensityBlusher = @"makeup_intensity_blusher",
|
||||
|
||||
//眉毛
|
||||
FUMakeUpChildStrengthKeyIntensityEyeBrow = @"makeup_intensity_eyeBrow",
|
||||
|
||||
//眼影
|
||||
FUMakeUpIntensityEye = @"makeup_intensity_eye",
|
||||
|
||||
//眼线
|
||||
FUMakeUpChildStrengthKeyIntensityEyeLiner = @"makeup_intensity_eyeLiner",
|
||||
|
||||
//睫毛
|
||||
FUMakeUpChildStrengthKeyIntensityEyelash = @"makeup_intensity_eyelash",
|
||||
|
||||
//高光
|
||||
FUMakeUpChildStrengthKeyIntensityHighlight = @"makeup_intensity_highlight",
|
||||
|
||||
//阴影
|
||||
FUMakeUpChildStrengthKeyIntensityShadow = @"makeup_intensity_shadow",
|
||||
|
||||
//美瞳
|
||||
FUMakeUpChildStrengthKeyIntensityPupil = @"makeup_intensity_pupil"
|
||||
)
|
||||
#endif /* FUMakeUpChildStrengthKey_h */
|
||||
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// FUMakeUpColorsKey1.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/2/1.
|
||||
//
|
||||
|
||||
#ifndef FUMakeUpColorsKey_h
|
||||
#define FUMakeUpColorsKey_h
|
||||
|
||||
#import "FUKeysDefine.h"
|
||||
|
||||
FUParamsKeysDefine(FUMakeUpColor,
|
||||
|
||||
//粉底
|
||||
FUMakeUpColorFoundationColor = @"makeup_foundation_color",
|
||||
|
||||
//口红颜色
|
||||
FUMakeUpColorLipColor = @"makeup_lip_color",
|
||||
|
||||
//口红颜色v2
|
||||
FUMakeUpColorLipColorV2 = @"makeup_lip_color_v2",
|
||||
|
||||
//口红颜色2
|
||||
FUMakeUpColorLipColor2 = @"makeup_lip_color2",
|
||||
|
||||
//腮红
|
||||
FUMakeUpColorBlusherColor = @"makeup_blusher_color",
|
||||
|
||||
//眉毛
|
||||
FUMakeUpColorEyeBrowColor = @"makeup_eyeBrow_color",
|
||||
|
||||
//眼影
|
||||
FUMakeUpColorEyeColor = @"makeup_eye_color",
|
||||
|
||||
//眼线
|
||||
FUMakeUpColorEyeLinerColor = @"makeup_eyeLiner_color",
|
||||
|
||||
//睫毛
|
||||
FUMakeUpColorEyelashColor = @"makeup_eyelash_color",
|
||||
|
||||
//高光
|
||||
FUMakeUpColorHighlightColor = @"makeup_highlight_color",
|
||||
|
||||
//阴影
|
||||
FUMakeUpColorShadowColor = @"makeup_shadow_color",
|
||||
|
||||
//美瞳
|
||||
FUMakeUpColorPupilColor = @"makeup_pupil_color"
|
||||
)
|
||||
|
||||
#endif /* FUMakeUpColorsKey_h */
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// FUMakeUpTextureKey.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/2/1.
|
||||
//
|
||||
|
||||
#ifndef FUMakeUpTextureKey_h
|
||||
#define FUMakeUpTextureKey_h
|
||||
|
||||
#import "FUKeysDefine.h"
|
||||
|
||||
FUParamsKeysDefine(FUMakeUpTextureKey,
|
||||
|
||||
//眉毛
|
||||
FUMakeUpTextureKeyTexBrow = @"tex_brow",
|
||||
|
||||
//眼影
|
||||
FUMakeUpTextureKeyTexEye1 = @"tex_eye",
|
||||
|
||||
//眼影2
|
||||
FUMakeUpTextureKeyTexEye2 = @"tex_eye2",
|
||||
|
||||
//眼影3
|
||||
FUMakeUpTextureKeyTexEye3 = @"tex_eye3",
|
||||
|
||||
//眼影4
|
||||
FUMakeUpTextureKeyTexEye4 = @"tex_eye4",
|
||||
|
||||
//美瞳
|
||||
FUMakeUpTextureKeyTexPupil = @"tex_pupil",
|
||||
|
||||
//睫毛
|
||||
FUMakeUpTextureKeyTexEyeLash = @"tex_eyeLash",
|
||||
|
||||
//眼线
|
||||
FUMakeUpTextureKeyTexEyeLiner = @"tex_eyeLiner",
|
||||
|
||||
//腮红1
|
||||
FUMakeUpTextureKeyTexBlusher1 = @"tex_blusher",
|
||||
|
||||
//腮红2
|
||||
FUMakeUpTextureKeyTexBlusher2 = @"tex_blusher2",
|
||||
|
||||
//粉底
|
||||
FUMakeUpTextureKeyTexFoundation = @"tex_foundation",
|
||||
|
||||
//高光
|
||||
FUMakeUpTextureKeyTexHighlight = @"tex_highlight",
|
||||
|
||||
//阴影
|
||||
FUMakeUpTextureKeyTexShadow = @"tex_shadow"
|
||||
)
|
||||
|
||||
#endif /* FUMakeUpTextureKey_h */
|
||||
193
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUMakeup.h
Executable file
193
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUMakeup.h
Executable file
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// FUMakeup.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/6.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUStruct.h"
|
||||
#import "FUMakeupValueDefine.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUMakeup : FUItem
|
||||
|
||||
/// 美妆开关,默认为YES
|
||||
@property (nonatomic, assign) BOOL isMakeupOn;
|
||||
|
||||
/// 在解绑妆容时是否清空除口红以外的妆容,NO表示不清空,YES表示清空,口红可由强度进行设置
|
||||
@property (nonatomic, assign) BOOL isClearMakeup;
|
||||
|
||||
/// 美妆分割,YES为开,NO为关,默认NO
|
||||
/// @note 建议在高端机型中使用
|
||||
@property (nonatomic, assign) BOOL makeupSegmentation;
|
||||
|
||||
/// 口红类型
|
||||
/// @see FUMakeupLipType
|
||||
@property (nonatomic, assign) FUMakeupLipType lipType;
|
||||
|
||||
/// 是否开启口红高光,YES为开,NO为关
|
||||
@property (nonatomic, assign) BOOL isLipHighlightOn;
|
||||
|
||||
/// 口红双色开关,NO为关闭,YES为开启
|
||||
/// @note 如果想使用咬唇,需要开启双色开关,并且将makeup_lip_color2的值都设置为0
|
||||
@property (nonatomic, assign) BOOL isTwoColor;
|
||||
|
||||
/// 眉毛变形类型
|
||||
/// @see FUMakeupBrowWarpType
|
||||
/// @note 如果browWarp为NO,眉毛变形类型设置失效
|
||||
@property (nonatomic, assign) FUMakeupBrowWarpType browWarpType;
|
||||
|
||||
/// 是否使用眉毛变形 YES为开 NO为关,默认为NO
|
||||
@property (nonatomic, assign) BOOL browWarp;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - 主题妆
|
||||
|
||||
@interface FUMakeup (Subject)
|
||||
|
||||
/// 更新组合装
|
||||
/// @param makeupPackage 子妆
|
||||
/// @param needCleanSubItem 是否清除老子妆
|
||||
- (void)updateMakeupPackage:(FUItem * __nullable)makeupPackage needCleanSubItem:(BOOL)needCleanSubItem;
|
||||
|
||||
/// 整体妆容程度值
|
||||
@property (nonatomic, assign) double intensity;
|
||||
|
||||
/// 整体妆容滤镜程度值
|
||||
@property (nonatomic, assign) double filterIntensity;
|
||||
|
||||
/// 局部妆容对象,属于组合装内部的具体部位(眉毛、眼镜、鼻子等)自定义设置
|
||||
@property (nonatomic, strong, nullable) FUItem *subEyebrow;
|
||||
@property (nonatomic, strong, nullable) FUItem *subEyeshadow;
|
||||
@property (nonatomic, strong, nullable) FUItem *subPupil;
|
||||
@property (nonatomic, strong, nullable) FUItem *subEyelash;
|
||||
@property (nonatomic, strong, nullable) FUItem *subEyeliner;
|
||||
@property (nonatomic, strong, nullable) FUItem *subBlusher;
|
||||
@property (nonatomic, strong, nullable) FUItem *subFoundation;
|
||||
@property (nonatomic, strong, nullable) FUItem *subHighlight;
|
||||
@property (nonatomic, strong, nullable) FUItem *subShadow;
|
||||
@property (nonatomic, strong, nullable) FUItem *subLip;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - 图层混合模式
|
||||
|
||||
@interface FUMakeup (blend)
|
||||
|
||||
@property (nonatomic, assign) FUMakeupBlendType blendTypeEyeshadow1;
|
||||
@property (nonatomic, assign) FUMakeupBlendType blendTypeEyeshadow2;
|
||||
@property (nonatomic, assign) FUMakeupBlendType blendTypeEyeshadow3;
|
||||
@property (nonatomic, assign) FUMakeupBlendType blendTypeEyeshadow4;
|
||||
@property (nonatomic, assign) FUMakeupBlendType blendTypeEyelash;
|
||||
@property (nonatomic, assign) FUMakeupBlendType blendTypeEyeliner;
|
||||
@property (nonatomic, assign) FUMakeupBlendType blendTypeBlusher1;
|
||||
@property (nonatomic, assign) FUMakeupBlendType blendTypeBlusher2;
|
||||
@property (nonatomic, assign) FUMakeupBlendType blendTypePupil;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - 子妆程度值
|
||||
|
||||
@interface FUMakeup (intensity)
|
||||
|
||||
/// 粉底程度值
|
||||
@property (nonatomic, assign) double intensityFoundation;
|
||||
|
||||
/// 口红程度值
|
||||
@property (nonatomic, assign) double intensityLip;
|
||||
|
||||
/// 口红高光程度值
|
||||
/// @note 暂时只用于lipType=FUMakeupLipTypeMoisturizing的情况
|
||||
@property (nonatomic, assign) double intensityLipHighlight;
|
||||
|
||||
/// 腮红程度值
|
||||
@property (nonatomic, assign) double intensityBlusher;
|
||||
|
||||
/// 眉毛程度值
|
||||
@property (nonatomic, assign) double intensityEyebrow;
|
||||
|
||||
/// 眼影程度值
|
||||
@property (nonatomic, assign) double intensityEyeshadow;
|
||||
|
||||
/// 眼线程度值
|
||||
@property (nonatomic, assign) double intensityEyeliner;
|
||||
|
||||
/// 睫毛程度值
|
||||
@property (nonatomic, assign) double intensityEyelash;
|
||||
|
||||
/// 高光程度值
|
||||
@property (nonatomic, assign) double intensityHighlight;
|
||||
|
||||
/// 阴影程度值
|
||||
@property (nonatomic, assign) double intensityShadow;
|
||||
|
||||
/// 美瞳程度值
|
||||
@property (nonatomic, assign) double intensityPupil;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - 子妆颜色
|
||||
|
||||
@interface FUMakeup (Color)
|
||||
|
||||
/// 粉底颜色
|
||||
@property (nonatomic, assign) FUColor foundationColor;
|
||||
|
||||
/// 口红颜色
|
||||
@property (nonatomic, assign) FUColor lipColor;
|
||||
|
||||
/// 口红颜色2
|
||||
@property (nonatomic, assign) FUColor lipColor2;
|
||||
|
||||
/// 腮红颜色
|
||||
@property (nonatomic, assign) FUColor blusherColor;
|
||||
|
||||
/// 眉毛颜色
|
||||
@property (nonatomic, assign) FUColor eyebrowColor;
|
||||
|
||||
/// 眼线颜色
|
||||
@property (nonatomic, assign) FUColor eyelinerColor;
|
||||
|
||||
/// 睫毛颜色
|
||||
@property (nonatomic, assign) FUColor eyelashColor;
|
||||
|
||||
/// 高光颜色
|
||||
@property (nonatomic, assign) FUColor highlightColor;
|
||||
|
||||
/// 阴影颜色
|
||||
@property (nonatomic, assign) FUColor shadowColor;
|
||||
|
||||
/// 美瞳颜色
|
||||
@property (nonatomic, assign) FUColor pupilColor;
|
||||
|
||||
/// 眼影特殊处理
|
||||
/// @note 如果is_two_color为1,会启用这个颜色,外圈颜色为color2,内圈颜色为color,如果color都为0,则外圈为透明,即为咬唇效果
|
||||
/// - Parameters:
|
||||
/// - color: 第一层眼影调色参数,数组的第四个值(对应alpha)为0时,会关闭这层的调色功能,大于0时会开启
|
||||
/// - color1: 第二层眼影调色参数,数组的第四个值(对应alpha)为0时,会关闭这层的调色功能,大于0时会开启,内部暂时未处理,使用color2和color3
|
||||
/// - color2: 第三层眼影调色参数,数组的第四个值(对应alpha)为0时,会关闭这层的调色功能,大于0时会开启
|
||||
/// - color3: 第四层眼影调色参数,数组的第四个值(对应alpha)为0时,会关闭这层的调色功能,大于0时会开启
|
||||
- (void)setEyeColor:(FUColor)color
|
||||
color1:(FUColor)color1
|
||||
color2:(FUColor)color2
|
||||
color3:(FUColor)color3;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUMakeup (landMark)
|
||||
|
||||
/// 这个参数控制是否使用修改过得landmark点,1为使用,0为不使用
|
||||
@property (nonatomic, assign) int isUserFix;
|
||||
|
||||
/// 这个参数为一个数组,需要客户端传递一个数组进去
|
||||
/// @note 传递的数组的长度为 150*人脸数,也就是将所有的点位信息存储的数组中传递进来
|
||||
@property (nonatomic, assign) FULandMark fixMakeUpData;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// FUMakeupValueDefine.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/3/4.
|
||||
//
|
||||
|
||||
#ifndef FUMakeupValueDefine_h
|
||||
#define FUMakeupValueDefine_h
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FUMakeupLipType) {
|
||||
FUMakeupLipTypeFOG = 0, //雾面
|
||||
FUMakeupLipTypeGlossy = 2, //润泽Ⅰ
|
||||
FUMakeupLipTypePearlyLustre = 3, //珠光
|
||||
FUMakeupLipTypeHightPerformance = 6, //高性能
|
||||
FUMakeupLipTypeMoisturizing = 7, //润泽Ⅱ
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FUMakeupBrowWarpType) {
|
||||
FUMakeupBrowWarpTypeArch = 0, //柳叶眉
|
||||
FUMakeupBrowWarpTypeSynophridia, //一字眉
|
||||
FUMakeupBrowWarpTypeDistantMountains, //小山眉
|
||||
FUMakeupBrowWarpTypeStandard, //标准眉
|
||||
FUMakeupBrowWarpTypeHelpShape, //扶形眉
|
||||
FUMakeupBrowWarpTypeDaily, //日常风
|
||||
FUMakeupBrowWarpTypeJapanese //日系风
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, FUMakeupBlendType) {
|
||||
FUMakeupBlendTypeInvalid = -1, //默认无效
|
||||
FUMakeupBlendTypeMultiply = 0, //正片叠底
|
||||
FUMakeupBlendTypeNormal, //正常混合
|
||||
FUMakeupBlendTypeOverlay, //叠加
|
||||
FUMakeupBlendTypeSoftLight, //柔光模式
|
||||
};
|
||||
|
||||
|
||||
#endif /* FUMakeupValueDefine_h */
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// FUMusicFilter.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/28.
|
||||
//
|
||||
|
||||
#import "FUSticker.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
/**
|
||||
* 音乐滤镜
|
||||
*/
|
||||
@interface FUMusicFilter : FUSticker
|
||||
/**
|
||||
* 设置音乐文件路径,但不播放,等到音乐滤镜在底层库渲染时自动播放音乐
|
||||
* 同步音乐和渲染效果
|
||||
*/
|
||||
@property (nonatomic, strong) NSString *musicPath;
|
||||
/**
|
||||
* 播放当前已经设置的音乐文件
|
||||
*/
|
||||
- (void)play;
|
||||
|
||||
/**
|
||||
* 继续播放
|
||||
*/
|
||||
- (void)resume;
|
||||
/**
|
||||
* 停止播放
|
||||
*/
|
||||
- (void)stop;
|
||||
/**
|
||||
* 暂停
|
||||
*/
|
||||
- (void)pause;
|
||||
/**
|
||||
* 获取播放进度
|
||||
*/
|
||||
- (float)playProgress;
|
||||
/**
|
||||
* 获取当前媒体播放时间
|
||||
*/
|
||||
- (NSTimeInterval)currentTime;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// FUBidirectionalMap.h
|
||||
// FUVideoEditor
|
||||
//
|
||||
// Created by Roy Zhang on 2020/4/15.
|
||||
// Copyright © 2020 Faceunity. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUOvonicMap : NSObject
|
||||
@property (nonatomic, strong) NSMutableDictionary *keysToValues;
|
||||
@property (nonatomic, strong) NSMapTable *valuesToKeys;
|
||||
@property (nonatomic, readonly) unsigned long long count;
|
||||
|
||||
+ (FUOvonicMap*)map;
|
||||
+ (FUOvonicMap*)mapWithDictionary:(NSDictionary *)dictionary;
|
||||
- (FUOvonicMap*)initWithDictionary:(NSDictionary *)dictionary;
|
||||
|
||||
- (void)createValuesToKeysMapping;
|
||||
- (id)objectForKeyedSubscript:(id)key;
|
||||
- (void)setObject:(id)object forKeyedSubscript:(id)key;
|
||||
- (void)removeObjectForKey:(id)key;
|
||||
- (id)keyForObject:(id)object;
|
||||
|
||||
- (NSArray *)allKeys;
|
||||
- (NSArray *)allValues;
|
||||
- (NSDictionary *)dictionary;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
33
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUParam.h
Executable file
33
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUParam.h
Executable file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// FUParam.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/17.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef enum : NSUInteger {
|
||||
FUParamTypeString,
|
||||
FUParamTypeDouble,
|
||||
FUParamTypeUInt64,
|
||||
FUParamTypeBufferByte,
|
||||
FUParamTypeBufferDouble,
|
||||
FUParamTypeBufferFloat,
|
||||
} FUParamType;
|
||||
|
||||
@interface FUParam : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString *name;
|
||||
|
||||
@property (nonatomic, assign) FUParamType type;
|
||||
|
||||
@property (nonatomic, strong) id paramValue;
|
||||
|
||||
+ (FUParam *)paramWithName:(NSString *)name value:(id)paramValue type:(FUParamType)type;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
82
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUPoster.h
Executable file
82
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUPoster.h
Executable file
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// FUPoster.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/8.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
#import <CoreGraphics/CGGeometry.h>
|
||||
#import "FURenderIO.h"
|
||||
|
||||
@class FUPoster;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@class UIImage, FUFaceRectInfo;
|
||||
|
||||
@protocol FUPosterProtocol <NSObject>
|
||||
|
||||
@optional
|
||||
/**
|
||||
* 检测输入照片人脸结果异常调用, 用于处理异常提示 UI逻辑.
|
||||
* code: -1, 人脸异常(检测到人脸但是角度不对返回-1),0: 未检测到人脸
|
||||
*/
|
||||
- (void)poster:(FUPoster *)poster inputImageTrackErrorCode:(int)code;
|
||||
|
||||
/**
|
||||
* 检测海报模版背景图片人脸结果(异常调用)
|
||||
* code: -1, 人脸异常(检测到人脸但是角度不对返回-1) 0: 未检测到人脸
|
||||
*/
|
||||
- (void)poster:(FUPoster *)poster tempImageTrackErrorCode:(int)code;
|
||||
|
||||
/**
|
||||
* 输入照片检测到单人脸回调此方法
|
||||
*/
|
||||
- (void)poster:(FUPoster *)poster trackedFaceInfo:(FUFaceRectInfo *)faceInfo;
|
||||
|
||||
/**
|
||||
* 输入照片检测到多张人脸回调此方法,用于UI层绘制多人脸 UI
|
||||
*/
|
||||
- (void)poster:(FUPoster *)poster trackedMultiFaceInfos:(NSArray <FUFaceRectInfo *> *)faceInfos;
|
||||
|
||||
/**
|
||||
* inputImage 和 蒙板image 合成的结果回调
|
||||
* data : 海报蒙板和照片合成之后的图片数据
|
||||
*/
|
||||
|
||||
- (void)poster:(FUPoster *)poster didRenderToImage:(UIImage *)image;
|
||||
|
||||
/**
|
||||
* 设置模板弯曲度,需要外部传入
|
||||
* return double 对象
|
||||
*/
|
||||
- (NSNumber *)renderOfWarp;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUPoster : FUItem
|
||||
@property (nonatomic, weak) id<FUPosterProtocol>delegate;
|
||||
/**
|
||||
* inputImage 需要替换包含人脸图片
|
||||
* templateImage 背景模板包含人脸的图片
|
||||
*/
|
||||
- (void)renderWithInputImage:(UIImage *)inputImage templateImage:(UIImage *)templateImage;
|
||||
|
||||
/**
|
||||
* 替换背景图片
|
||||
*/
|
||||
- (void)changeTempImage:(UIImage *)tempImage;
|
||||
|
||||
/**
|
||||
* 计算人脸区域
|
||||
*/
|
||||
+ (CGRect)cacluteRectWithIndex:(int)index height:(int)originHeight width:(int)orighnWidth;
|
||||
|
||||
/**
|
||||
* 选择某张具体的人脸,
|
||||
* faceId 通过 checkPosterWithFaceIds:rectsMap 获取
|
||||
*/
|
||||
- (void)chooseFaceID:(int)faceID;
|
||||
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// FUQualitySticker.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/4/14.
|
||||
//
|
||||
|
||||
#import "FUSticker.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUQualitySticker : FUSticker
|
||||
@property (nonatomic, assign) BOOL isFlipPoints; //点位镜像,0为关闭,1为开启
|
||||
@property (nonatomic, assign) BOOL is3DFlipH; //翻转模型
|
||||
|
||||
/// 精品贴纸点击屏幕特殊效果
|
||||
- (void)clickToChange;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
144
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FURenderIO.h
Executable file
144
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FURenderIO.h
Executable file
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// FURenderInput.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by liuyang on 2021/1/4.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import "CNamaSDK.h"
|
||||
|
||||
typedef enum : NSUInteger {
|
||||
FUImageBufferFormatRGBA,
|
||||
FUImageBufferFormatBGRA,
|
||||
FUImageBufferFormatYUV420V,
|
||||
FUImageBufferFormatYUV420F,
|
||||
FUImageBufferFormatYUVI420,
|
||||
} FUImageBufferFormat;
|
||||
|
||||
typedef enum : NSUInteger {
|
||||
FUImageOrientationUP,
|
||||
FUImageOrientationRight,
|
||||
FUImageOrientationDown,
|
||||
FUImageOrientationLeft
|
||||
} FUImageOrientation;
|
||||
|
||||
/// CPU image 数据
|
||||
struct FUImageBuffer {
|
||||
Byte *buffer0; // 格式与传入 buffer 类型对应关系:RGBA: rgba_buffer; BGRA: bgra_buffer; YUV420V/YUV420F/YUVI420: y_buffer
|
||||
size_t stride0; // 格式与传入 stride 类型对应关系:RGBA: rgba_stride; BGRA: bgra_stride; YUV420V/YUV420F/YUVI420: y_stride
|
||||
|
||||
Byte *buffer1; // 格式与传入 buffer 类型对应关系:RGBA/BGRA: NULL; YUV420V/YUV420F: uv_buffer; YUVI420: u_buffer
|
||||
size_t stride1; // 格式与传入 stride 类型对应关系:RGBA/BGRA: 0; YUV420V/YUV420F: uv_stride; YUVI420: u_stride
|
||||
|
||||
Byte *buffer2; // 格式与传入 buffer 类型对应关系:RGBA/BGRA: NULL; YUV420V/YUV420F: NULL; YUVI420: v_buffer
|
||||
size_t stride2; // 格式与传入 stride 类型对应关系:RGBA/BGRA: 0; YUV420V/YUV420F: 0; YUVI420: v_stride
|
||||
|
||||
CGSize size; // 图像宽高
|
||||
FUImageBufferFormat format; // 图像格式
|
||||
|
||||
};
|
||||
typedef struct FUImageBuffer FUImageBuffer;
|
||||
|
||||
FUImageBuffer FUImageBufferMakeRGBA(Byte *buffer0, size_t width, size_t height, size_t stride0);
|
||||
FUImageBuffer FUImageBufferMakeBGRA(Byte *buffer0, size_t width, size_t height, size_t stride0);
|
||||
FUImageBuffer FUImageBufferMakeYUV420F(Byte *buffer0, Byte *buffer1, size_t width, size_t height, size_t stride0, size_t stride1);
|
||||
FUImageBuffer FUImageBufferMakeYUV420V(Byte *buffer0, Byte *buffer1, size_t width, size_t height, size_t stride0, size_t stride1);
|
||||
FUImageBuffer FUImageBufferMakeI420(Byte *buffer0, Byte *buffer1, Byte *buffer2, size_t width, size_t height, size_t stride0, size_t stride1, size_t stride2);
|
||||
FUImageBuffer FUImageBufferMake(Byte *buffer0, Byte *buffer1, Byte *buffer2, size_t width, size_t height, size_t stride0, size_t stride1, size_t stride2, FUImageBufferFormat format);
|
||||
|
||||
|
||||
/// 纹理数据
|
||||
struct FUTexture {
|
||||
GLuint ID; // 纹理ID
|
||||
CGSize size; // 纹理宽高
|
||||
};
|
||||
typedef struct FUTexture FUTexture;
|
||||
|
||||
#pragma -mark FURenderConfig
|
||||
@interface FURenderConfig : NSObject
|
||||
|
||||
/// 自定义输出结果的大小,当前只会对输出的纹理及pixelBuffer有效
|
||||
@property (nonatomic, assign) CGSize customOutputSize;
|
||||
|
||||
/// 当前图片是否来源于前置摄像头,默认为 NO
|
||||
@property (nonatomic, assign) BOOL isFromFrontCamera;
|
||||
|
||||
/// 当前图片是否来源于镜像摄像头,默认为 NO
|
||||
@property (nonatomic, assign) BOOL isFromMirroredCamera;
|
||||
|
||||
/// 原始图像的朝向
|
||||
@property (nonatomic, assign) FUImageOrientation imageOrientation;
|
||||
|
||||
/// 贴纸水平镜像
|
||||
@property (nonatomic, assign) BOOL stickerFlipH;
|
||||
|
||||
/// 贴纸垂直镜像
|
||||
@property (nonatomic, assign) BOOL stickerFlipV;
|
||||
|
||||
/// 重力开关,开启此功能可以根据已设置的 imageRotation 自动适配AI检测的方向。
|
||||
@property (nonatomic, assign) BOOL gravityEnable;
|
||||
|
||||
/// 设置为YES 只会生效美颜结果
|
||||
@property (nonatomic, assign) BOOL onlyRenderBeauty;
|
||||
|
||||
/// 设置输入pixelBuffer/imageBuffer的旋转方向,以使buffer数据与textureTransform作用后纹理的方向一致,该参数仅用于AI算法检测,不会改变buffer的方向或镜像属性
|
||||
@property (nonatomic, assign) TRANSFORM_MATRIX bufferTransform;
|
||||
|
||||
/// 设置输入纹理的旋转及镜像信息,设置该属性会影响输出纹理的方向。默认基于 CPU 图像创建的纹理与CPU 图像成上下镜像关系,此时 textureTransform 对应的值为 DEFAULT,以此类推,如果对默认生成的纹理做了其他变换,则将该参数设置为对应的变换即可。
|
||||
@property (nonatomic, assign) TRANSFORM_MATRIX textureTransform;
|
||||
|
||||
/// 设置输出pixelBuffer/imageBuffer的旋转方向,以使buffer数据与textureTransform作用后纹理的方向一致,该参数仅用于AI算法检测,不会改变buffer的方向或镜像属性
|
||||
@property (nonatomic, assign) TRANSFORM_MATRIX outputTransform;
|
||||
|
||||
/// 是否渲染到当前的FBO,设置为YES时,返回的 FURenderOutput 内的所有数据均为空值。
|
||||
@property (nonatomic, assign) BOOL renderToCurrentFBO;
|
||||
|
||||
//是否读回到输入的buffer, 如果手机在后台状态也不回写数据,返回的output对象内部buffer为空。
|
||||
@property (nonatomic, assign) BOOL readBackToPixelBuffer;
|
||||
|
||||
/// 设置为YES 且 renderToCurrentFBO 为 NO 时,只会输出纹理,不会输出CPU层的图像。
|
||||
@property (nonatomic, assign) BOOL onlyOutputTexture;
|
||||
|
||||
/// 控制输出图像是否保留透明信息,默认值为NO,可能会输出不透明的图像,开启该参数可以保持图像中透明信息。
|
||||
@property (nonatomic, assign) BOOL keepAlpha;
|
||||
|
||||
/// 如果 renderKit 有 glDisplayView ,控制绘制结果将直接渲染到 glDisplayView
|
||||
@property (nonatomic, assign) BOOL autoDisplay;
|
||||
|
||||
@end
|
||||
|
||||
#pragma -mark FURenderInput
|
||||
@interface FURenderInput : NSObject
|
||||
|
||||
/// 输入的纹理
|
||||
@property (nonatomic, assign) FUTexture texture;
|
||||
|
||||
/// 输入的 pixelBuffer
|
||||
@property (nonatomic, assign) CVPixelBufferRef pixelBuffer;
|
||||
|
||||
/// 输入的 imageBuffer,如果同时传入了 pixelBuffer,将优先使用 pixelBuffer
|
||||
/// 输入 imageBuffer,在 renderConfig 的 onlyOutputTexture 为 NO 时,render 结果会直接读会输入的 imageBuffer,大小格式与输入均保持一致。
|
||||
@property (nonatomic, assign) FUImageBuffer imageBuffer;
|
||||
|
||||
/// 设置render相关的输入输出配置,详细参数请查看 FURenderConfig 类的接口注释。
|
||||
@property (nonatomic, strong, readonly) FURenderConfig *renderConfig;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma -mark FURenderOutput
|
||||
@interface FURenderOutput : NSObject
|
||||
|
||||
/// 输出的纹理
|
||||
@property (nonatomic, assign) FUTexture texture;
|
||||
|
||||
/// 输出的 pixelBuffer
|
||||
@property (nonatomic, assign) CVPixelBufferRef pixelBuffer;
|
||||
|
||||
/// 输出的 imageBuffer,内部数据与输入的 imageBuffer 一致。
|
||||
@property (nonatomic, assign) FUImageBuffer imageBuffer;
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// FURenderKit-umbrella.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by 项林平 on 2022/2/21.
|
||||
//
|
||||
|
||||
#import "FURenderKit.h"
|
||||
#import "FUAIKit.h"
|
||||
|
||||
#import "CNamaSDK.h"
|
||||
#import "FURenderer.h"
|
||||
|
||||
#import "FURenderIO.h"
|
||||
#import "FUConfig.h"
|
||||
#import "FUAIConfig.h"
|
||||
#import "FUSetupConfig.h"
|
||||
#import "FUInternalCameraSetting.h"
|
||||
|
||||
#import "FUKeysDefine.h"
|
||||
#import "FUDeformationKeys.h"
|
||||
#import "FUBeautyPropertyModeDefine.h"
|
||||
#import "FUFilterDefineKey.h"
|
||||
#import "FUMakeupValueDefine.h"
|
||||
#import "FUMakeUpTextureKey.h"
|
||||
#import "FUMakeUpColorsKey.h"
|
||||
#import "FUBodyBeautyDefineKeys.h"
|
||||
|
||||
#import "FULightMakeUpTextureKeyDefineKey.h"
|
||||
#import "FUHairDefineKey.h"
|
||||
#import "FUMakeUpChildStrengthDefineKey.h"
|
||||
#import "FUAvatarColorKeys.h"
|
||||
#import "FUFacepupKeys.h"
|
||||
#import "FUStruct.h"
|
||||
|
||||
#import "FURenderableObject.h"
|
||||
#import "FUItem.h"
|
||||
#import "FUCustomBackground.h"
|
||||
#import "FUMusicFilter.h"
|
||||
#import "FUStickerContainer.h"
|
||||
#import "FUFaceRectInfo.h"
|
||||
#import "FUParam.h"
|
||||
#import "FUActionRecognition.h"
|
||||
#import "FUSticker.h"
|
||||
#import "FUGreenScreen.h"
|
||||
#import "FUBodyBeauty.h"
|
||||
#import "FUAnimoji.h"
|
||||
#import "FUQualitySticker.h"
|
||||
#import "FUAnimation.h"
|
||||
#import "FUHairBeauty.h"
|
||||
#import "FUBeauty.h"
|
||||
#import "FUBeauty-Deprecated.h"
|
||||
#import "FUComicFilter.h"
|
||||
#import "FUAISegment.h"
|
||||
#import "FUMakeup.h"
|
||||
#import "FUBackground.h"
|
||||
#import "FULightMakeup.h"
|
||||
#import "FUScene.h"
|
||||
#import "FUSceneCamera.h"
|
||||
#import "FUAvatar.h"
|
||||
#import "FUAvatarMakeup.h"
|
||||
#import "FUFacialFeatures.h"
|
||||
#import "FUGroupAnimation.h"
|
||||
#import "FUPoster.h"
|
||||
#import "FUCameraAnimation.h"
|
||||
#import "FUGesture.h"
|
||||
#import "FULight.h"
|
||||
|
||||
#import "FUCaptureCamera.h"
|
||||
#import "FUGLDisplayView.h"
|
||||
#import "FUGLContext.h"
|
||||
#import "FURenderQueue.h"
|
||||
|
||||
#import "metamacros.h"
|
||||
#import "FUImageHelper.h"
|
||||
#import "FUOvonicMap.h"
|
||||
#import "FUCLIColor.h"
|
||||
#import "FUAvatarCheck.h"
|
||||
#import "FUVideoComponentDefines.h"
|
||||
#import "FUVideoReader.h"
|
||||
#import "FUVideoWriter.h"
|
||||
#import "FUVideoProcessor.h"
|
||||
|
||||
#import "UIImage+FURenderKit.h"
|
||||
#import "FUItem+createTexture.h"
|
||||
#import "UIDevice+FURenderKit.h"
|
||||
301
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FURenderKit.h
Executable file
301
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FURenderKit.h
Executable file
@@ -0,0 +1,301 @@
|
||||
//
|
||||
// FURenderKit.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by ly-Mac on 2020/12/2.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUScene.h"
|
||||
#import "FUAvatarCheck.h"
|
||||
#import "FUGroupAnimation.h"
|
||||
#import "FUCaptureCamera.h"
|
||||
#import "FUInternalCameraSetting.h"
|
||||
#import "FUGLDisplayView.h"
|
||||
#import "FUSetupConfig.h"
|
||||
#import "FURenderIO.h"
|
||||
|
||||
#import "FUBeauty.h"
|
||||
#import "FUMakeup.h"
|
||||
|
||||
#import "FUStickerContainer.h"
|
||||
#import "FULightMakeup.h"
|
||||
#import "FUComicFilter.h"
|
||||
#import "FUHairBeauty.h"
|
||||
#import "FUGreenScreen.h"
|
||||
#import "FUBodyBeauty.h"
|
||||
#import "FUActionRecognition.h"
|
||||
#import "FUPoster.h"
|
||||
#import "FUMusicFilter.h"
|
||||
#import "FUAnimoji.h"
|
||||
|
||||
#import "FUGesture.h"
|
||||
#import "FUFaceRectInfo.h"
|
||||
#import "FUAISegment.h"
|
||||
#import "UIImage+FURenderKit.h"
|
||||
#import "FUImageHelper.h"
|
||||
#import "UIDevice+FURenderKit.h"
|
||||
#import "FURenderQueue.h"
|
||||
|
||||
#import "FUAIKit.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class FURenderKit;
|
||||
|
||||
FUParamsKeysDefine(FUDynamicQualityParamKey,
|
||||
FUDynamicQualityParamTriggerFPSKey = @"trigger_fps",
|
||||
FUDynamicQualityParamChangeSpeedKey = @"quality_change_speed",
|
||||
FUDynamicQualityParamChangeSmoothTimeKey = @"quality_change_smooth_time"
|
||||
)
|
||||
|
||||
#pragma mark - 内部相机render相关协议
|
||||
|
||||
@protocol FURenderKitDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
/// 使用内部相机时,即将处理图像时输入回调
|
||||
- (void)renderKitWillRenderFromRenderInput:(FURenderInput *)renderInput;
|
||||
|
||||
/// 使用内部相机时,处理图像后的输出回调
|
||||
- (void)renderKitDidRenderToOutput:(FURenderOutput *)renderOutput;
|
||||
|
||||
/// 使用内部相机时,内部是否进行render处理,返回NO,将直接输出原图。
|
||||
- (BOOL)renderKitShouldDoRender;
|
||||
|
||||
@end
|
||||
|
||||
@interface FURenderKit : NSObject
|
||||
|
||||
/// 3D场景实例,设置前需要先将 scene 通过 addScene 接口添加到 renderKit
|
||||
@property (nonatomic, strong, nullable) FUScene *currentScene;
|
||||
|
||||
/// 通过 addScene 接口添加到renderKit的3D场景数组
|
||||
@property (nonatomic, strong, readonly) NSArray *scenes;
|
||||
|
||||
/// 美颜
|
||||
@property (nonatomic, strong, nullable) FUBeauty *beauty;
|
||||
|
||||
/// 美妆
|
||||
@property (nonatomic, strong, nullable) FUMakeup *makeup;
|
||||
|
||||
/// 道具贴纸、AR面具、搞笑大头、哈哈镜等道具的容器对象
|
||||
@property (nonatomic, strong, readonly) FUStickerContainer *stickerContainer;
|
||||
|
||||
/// 轻美妆
|
||||
@property (nonatomic, strong, nullable) FULightMakeup *lightMakeup;
|
||||
|
||||
/// 动漫滤镜
|
||||
@property (nonatomic, strong, nullable) FUComicFilter *comicFilter;
|
||||
|
||||
/// 美发
|
||||
@property (nonatomic, strong, nullable) FUHairBeauty *hairBeauty;
|
||||
|
||||
/// 绿慕
|
||||
@property (nonatomic, strong, nullable) FUGreenScreen *greenScreen;
|
||||
|
||||
/// 音乐滤镜
|
||||
@property (nonatomic, strong, nullable) FUMusicFilter *musicFilter;
|
||||
|
||||
/// 美体
|
||||
@property (nonatomic, strong, nullable) FUBodyBeauty *bodyBeauty;
|
||||
|
||||
/// 动作识别
|
||||
@property (nonatomic, strong, nullable) FUActionRecognition *actionRecognition;
|
||||
|
||||
/// 人像分割
|
||||
@property (nonatomic, strong, nullable) FUAISegment *segmentation;
|
||||
|
||||
/// 抗锯齿道具
|
||||
@property (nonatomic, strong, nullable) FUItem *antiAliasing;
|
||||
|
||||
/// 多重采样等级,默认为0
|
||||
@property (nonatomic, assign) int msaaLevel;
|
||||
|
||||
/// 内部渲染视图
|
||||
/// @note 如果使用 glDisplayView 渲染,需要由用户自己创建并赋值给该属性,当内部或外部调用 renderWithInput 时,会自动显示在该 View 中。
|
||||
@property (nonatomic, strong, nullable) FUGLDisplayView *glDisplayView;
|
||||
|
||||
#pragma mark - 内部相机与回调
|
||||
|
||||
/// internalCameraSetting 有默认值,用户按需修改对应配置即可。
|
||||
/// @see FUInternalCameraSetting
|
||||
@property (nonatomic, strong, readonly) FUInternalCameraSetting *internalCameraSetting;
|
||||
|
||||
/// 暂停内部渲染循环,不会影响外部对renderWithInput的调用。
|
||||
@property (nonatomic, assign) BOOL pause;
|
||||
|
||||
/// 内部相机,当 使用内部相机,并且 internalCameraSetting 中 useVirtualCamera == NO 时,才会开启内部真实相机。
|
||||
@property (nonatomic, strong, readonly, nullable) FUCaptureCamera *captureCamera;
|
||||
|
||||
/// 内部渲染回调,只有使用内部相机时对应的代理方法才会执行
|
||||
/// @see FURenderKitDelegate
|
||||
@property (nonatomic, weak, nullable) id<FURenderKitDelegate> delegate;
|
||||
|
||||
#pragma mark - setup and destroy
|
||||
|
||||
/// FURenderKit 单例
|
||||
+ (instancetype)shareRenderKit;
|
||||
|
||||
/// SDK 初始化
|
||||
/// @param setupConfig 初始化配置
|
||||
/// @see FUSetupConfig
|
||||
+ (BOOL)setupWithSetupConfig:(FUSetupConfig *)setupConfig;
|
||||
|
||||
/// setupconfig 里面需要填入offLinePath 离线鉴权包地址
|
||||
/// @return 第一次鉴权成功后的文件
|
||||
+ (NSData *)setupLocalWithSetupConfig:(FUSetupConfig *)setupConfig;
|
||||
|
||||
/// 内部调用fuSetupInternalCheck 初始化鉴权
|
||||
/// @return NO 失败, YES成功
|
||||
+ (BOOL)setupInternalCheckWithSetupConfig:(FUSetupConfig *)setupConfig;
|
||||
|
||||
/// 内部调用fuSetupInternalCheckPackageBind 初始化鉴权
|
||||
/// @param setupConfig 初始化配置
|
||||
/// @return NO 失败, YES成功
|
||||
+ (BOOL)setupInternalCheckPackageBindWithSetupConfig:(FUSetupConfig *)setupConfig;
|
||||
|
||||
/// 销毁 FURenderKit,释放内存,同时会清空所有的特效模型。
|
||||
+ (void)destroy;
|
||||
|
||||
/// 清空所有的特效模型:美颜、美型、美妆、3D场景与形象等。
|
||||
+ (void)clear;
|
||||
|
||||
#pragma mark - version
|
||||
/// 获取版本信息
|
||||
/// @return 版本信息
|
||||
+ (NSString *)getVersion;
|
||||
|
||||
/// 设置 log 等级
|
||||
/// @param logLevel log 等级
|
||||
+ (void)setLogLevel:(FULOGLEVEL)logLevel;
|
||||
|
||||
/// 设置 log 保存路径
|
||||
/// @param filePath log 保存路径
|
||||
+ (void)setLogFilePath:(NSString *)filePath;
|
||||
|
||||
#pragma mark - scene
|
||||
|
||||
/// 异步添加场景,添加完成后需要将场景设置为 currentScene 才可以生效
|
||||
/// @param scene 被添加的场景
|
||||
/// @param completion 添加完成的回调
|
||||
- (void)addScene:(FUScene *)scene completion:(nullable void(^)(BOOL success))completion;
|
||||
|
||||
/// 移除场景,如果被移除的场景为当前场景,当前渲染效果也会失效。
|
||||
/// @param scene 需要被移除的场景
|
||||
/// @param completion 移除完成的回调
|
||||
- (void)removeScene:(FUScene *)scene completion:(nullable void(^)(BOOL success))completion;
|
||||
|
||||
/// 替换场景,如果需要让新的场景生效,需要将其设置为 currentScene
|
||||
/// @param scene 被替换的场景,为空时直接添加新的场景
|
||||
/// @param newScene 新的场景,为空时直接移除被替换的场景
|
||||
/// @param completion 替换成功的回调
|
||||
- (void)replaceScene:(nullable FUScene *)scene withNewScene:(nullable FUScene *)newScene completion:(nullable void(^)(BOOL success))completion;
|
||||
|
||||
#pragma mark - internalCamera
|
||||
|
||||
/// 开启内部相机,相机配置请修改 internalCameraSetting 相关属性
|
||||
/// @see FUInternalCameraSetting
|
||||
- (void)startInternalCamera;
|
||||
|
||||
/// 关闭内部相机
|
||||
- (void)stopInternalCamera;
|
||||
|
||||
#pragma mark - Record && capture
|
||||
|
||||
/// 开始录像
|
||||
/// @param filePath 录像保存地址
|
||||
+ (void)startRecordVideoWithFilePath:(NSString *)filePath;
|
||||
|
||||
/// 结束录像
|
||||
/// @param complention 录制结束回调
|
||||
+ (void)stopRecordVideoComplention:(void(^)(NSString *filePath))complention;
|
||||
|
||||
/// 获取单帧图像
|
||||
+ (UIImage *)captureImage;
|
||||
|
||||
#pragma mark - renderWithInput
|
||||
|
||||
/// 核心渲染接口
|
||||
/// @discussion 当贴纸、美颜、美型、美妆、3D场景与形象配置到 RenderKit之后,调用该接口会把效果作用于输出的结果中。支持输入单纹理、纹理+imageBuffer、纹理+pixelBuffer、单imageBuffer、单pixelBuffer,输出与输入相对应,也可以支持只输出纹理、或渲染到当前FBO。
|
||||
/// @param input 输入图像,类型为 FURenderInput
|
||||
/// @return 输出图像结果,类型为 FURenderOutput
|
||||
- (FURenderOutput *)renderWithInput:(FURenderInput *)input;
|
||||
|
||||
#pragma mark - Performance
|
||||
|
||||
/// 当前设备性能等级
|
||||
+ (FUDevicePerformanceLevel)devicePerformanceLevel;
|
||||
|
||||
/// 美妆效果覆盖开关,默认打开
|
||||
/// @note 当多个包含美妆效果的 bundle 互相影响时可以调用该接口设置为 YES,否则可以设为 NO
|
||||
+ (void)setMakeupCoverResourceEnabled:(BOOL)enabled;
|
||||
|
||||
/// 动态调节质量开关
|
||||
/// @param enabled YES / NO
|
||||
/// @note 目前只用于美颜,开启时会自动动态调节
|
||||
+ (void)setDynamicQualityControlEnabled:(BOOL)enabled;
|
||||
|
||||
/// 动态调节质量配置
|
||||
/// @param params 详细说明:
|
||||
/// key: 参考FUDynamicQualityParamKey
|
||||
/// value 说明:
|
||||
/// 1. 触发帧率,低于该帧率时会触发动态调节,大于0,默认 25
|
||||
/// 2. 变化速率,大于0,默认 1.7
|
||||
/// 3. 变化平滑度,大于0,默认 2.5
|
||||
+ (void)setDynamicQualityParams:(NSDictionary *)params;
|
||||
|
||||
/// ARMeshV2 开关
|
||||
/// @note 建议高端机型打开
|
||||
/// @note 目前版本不建议调用,建议使用 FUAIKit 的 setFaceAlgorithmConfig 接口设置
|
||||
+ (void)setARMeshV2Enabled:(BOOL)enabled;
|
||||
|
||||
|
||||
#pragma mark - Others
|
||||
|
||||
/// 获取证书里面的模块权限
|
||||
/// @return code get i-th code, currently available for 0 and 1
|
||||
+ (int)getModuleCode:(int)code;
|
||||
|
||||
/// 获取错误码
|
||||
/// @return 错误码
|
||||
+ (int)getSystemError;
|
||||
|
||||
/// 获取错误信息
|
||||
/// @return 错误信息
|
||||
+(NSString *)getSystemErrorString;
|
||||
|
||||
+ (int)profileGetNumTimers;
|
||||
|
||||
+ (long long)profileGetTimerAverage:(int)index;
|
||||
|
||||
/// 设置缓存目录,提升加载模型速度
|
||||
/// @param directory 可读写目录路径
|
||||
+ (void)setCacheDirectory:(NSString *)directory;
|
||||
|
||||
|
||||
#pragma mark - frame time profile
|
||||
|
||||
/// 开启/关闭算法耗时统计功能,默认关闭
|
||||
/// @param enable YES开启 NO关闭
|
||||
+ (void)setFrameTimeProfileEnable:(BOOL)enable;
|
||||
|
||||
/// 设置算法耗时输出到控制台
|
||||
+ (void)setFrameTimeProfileAutoReportToConsole;
|
||||
|
||||
/// 设置算法耗时输出到文件
|
||||
/// @param filePath 文件路径
|
||||
+ (void)setFrameTimeProfileAutoReportToFile:(NSString *_Nonnull)filePath;
|
||||
|
||||
/// 设置算法耗时打印间隔,默认为300
|
||||
/// @param interval 时间间隔
|
||||
+ (void)setFrameTimeProfileReportInterval:(int)interval;
|
||||
|
||||
/// 开启/关闭算法耗时统计详细信息,默认关闭
|
||||
/// @param enable YES开启 NO关闭
|
||||
+ (void)setFrameTimeProfileReportDetailsEnable:(BOOL)enable;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// FURenderQueue.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by liuyang on 2022/6/8.
|
||||
//
|
||||
// 渲染队列,可以使用该队列处理单帧同步效果
|
||||
//
|
||||
|
||||
#import "FUSerialQueue.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FURenderQueue : FUSerialQueue
|
||||
+ (void)sync:(dispatch_block_t)block;
|
||||
|
||||
+ (void)async:(dispatch_block_t)block;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// FURenderableObject.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by liuyang on 2021/1/15.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FURenderableObject : NSObject
|
||||
|
||||
@property (nonatomic, assign) BOOL enable;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
916
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FURenderer.h
Executable file
916
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FURenderer.h
Executable file
@@ -0,0 +1,916 @@
|
||||
//
|
||||
// FURenderer.h
|
||||
//
|
||||
// Created by ly on 16/11/2.
|
||||
// Copyright © 2016年 liuyang. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <GLKit/GLKit.h>
|
||||
#import "CNamaSDK.h"
|
||||
|
||||
typedef struct {
|
||||
CVPixelBufferRef pixelBuffer;
|
||||
GLuint bgraTextureHandle;
|
||||
} FUOutput;
|
||||
|
||||
typedef enum {
|
||||
FUFormatBGRABuffer = FU_FORMAT_BGRA_BUFFER,
|
||||
FUFormatRGBABuffer = FU_FORMAT_RGBA_BUFFER,
|
||||
FUFormatNV12Buffer = FU_FORMAT_NV12_BUFFER,
|
||||
FUFormatI420Buffer = FU_FORMAT_I420_BUFFER,
|
||||
FUFormatRGBATexture = FU_FORMAT_RGBA_TEXTURE,
|
||||
} FUFormat;
|
||||
|
||||
typedef enum {
|
||||
FURotationMode0 = FU_ROTATION_MODE_0,
|
||||
FURotationMode90 = FU_ROTATION_MODE_90,
|
||||
FURotationMode180 = FU_ROTATION_MODE_180,
|
||||
FURotationMode270 = FU_ROTATION_MODE_270,
|
||||
} FURotationMode;
|
||||
|
||||
__attribute__((visibility("default"))) @interface FURotatedImage : NSObject
|
||||
|
||||
@property void* mData;
|
||||
@property int mWidth;
|
||||
@property int mHeight;
|
||||
|
||||
- (instancetype)init;
|
||||
|
||||
@end
|
||||
;
|
||||
|
||||
__attribute__((visibility("default"))) @interface FUAvatarInfo : NSObject {
|
||||
@public
|
||||
float landmarks[150];
|
||||
float identity[75];
|
||||
float expression[56];
|
||||
float translation[3];
|
||||
float rotation[4];
|
||||
float rotationMode[1];
|
||||
float pupilPos[2];
|
||||
int isValid;
|
||||
|
||||
TAvatarInfo info;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
__attribute__((visibility("default"))) @interface FURenderer : NSObject
|
||||
|
||||
/**
|
||||
获取 FURenderer 单例
|
||||
|
||||
@return FURenderer 单例
|
||||
*/
|
||||
+ (FURenderer*)shareRenderer;
|
||||
|
||||
/**
|
||||
context切换
|
||||
*/
|
||||
- (void)setBackCurrentContext;
|
||||
- (void)setUpCurrentContext;
|
||||
|
||||
/**
|
||||
初始化接口1:
|
||||
- 初始化 SDK,并对 SDK 进行授权,在调用其他接口前必须要先进行初始化。
|
||||
- 使用该接口进行初始化的话,需要在代码中配置 EAGLContext
|
||||
环境,并且保证我们的接口是在同一个 EAGLContext 下调用的
|
||||
|
||||
@param data v3.bundle 对应的二进制数据地址
|
||||
@param dataSize v3.bundle 数据的字节数
|
||||
@param ardata 该参数已舍弃,传 NULL 即可
|
||||
@param package 密钥数组,必须配置好密钥,SDK 才能正常工作
|
||||
@param size 密钥数组大小
|
||||
@return 初始化结果,为0则初始化失败,大于0则初始化成功
|
||||
*/
|
||||
- (int)setupWithData:(void*)data
|
||||
dataSize:(int)dataSize
|
||||
ardata:(void*)ardata
|
||||
authPackage:(void*)package
|
||||
authSize:(int)size;
|
||||
|
||||
/**
|
||||
初始化接口2:
|
||||
- 初始化 SDK,并对 SDK 进行授权,在调用其他接口前必须要先进行初始化。
|
||||
- 与 初始化接口1 相比此接口新增 shouldCreate
|
||||
参数,如果传入YES我们将在内部创建并持有一个 EAGLContext,无需外部再创建
|
||||
EAGLContext 环境。
|
||||
|
||||
@param data v3.bundle 对应的二进制数据地址
|
||||
@param dataSize v3.bundle 数据的字节数
|
||||
@param ardata 该参数已废弃,传 NULL 即可
|
||||
@param package 密钥数组,必须配置好密钥,SDK 才能正常工作
|
||||
@param size 密钥数组大小
|
||||
@param shouldCreate 如果设置为 YES,我们会在内部创建并持有一个
|
||||
EAGLContext,OpenGL相关操作建议所用OC层接口
|
||||
(注:OC接口会切换到内部创建的EAGLContext上执行,防止多EAGLContext异常问题)
|
||||
@return 初始化结果,为0则初始化失败,大于0则初始化成功
|
||||
*/
|
||||
- (int)setupWithData:(void*)data
|
||||
dataSize:(int)dataSize
|
||||
ardata:(void*)ardata
|
||||
authPackage:(void*)package
|
||||
authSize:(int)size
|
||||
shouldCreateContext:(BOOL)shouldCreate;
|
||||
|
||||
/**
|
||||
初始化接口3:
|
||||
- 初始化SDK,并对 SDK 进行授权,在调用其他接口前必须要先进行初始化。
|
||||
- 与 初始化接口2 相比改为通过 v3.bundle
|
||||
的文件路径进行初始化,并且删除了废弃的 ardata 参数。
|
||||
|
||||
@param v3path v3.bundle 对应的文件路径
|
||||
@param package 密钥数组,必须配置好密钥,SDK 才能正常工作
|
||||
@param size 密钥数组大小
|
||||
@param shouldCreate 如果设置为 YES,我们会在内部创建并持有一个
|
||||
EAGLContext,OpenGL相关操作建议所用OC层接口
|
||||
(注:OC接口会切换到内部创建的EAGLContext上执行,防止多EAGLContext异常问题)
|
||||
@return 初始化结果,为0则初始化失败,大于0则初始化成功
|
||||
*/
|
||||
- (int)setupWithDataPath:(NSString*)v3path
|
||||
authPackage:(void*)package
|
||||
authSize:(int)size
|
||||
shouldCreateContext:(BOOL)shouldCreate;
|
||||
|
||||
/**
|
||||
初始化接口4:
|
||||
|
||||
- 初始化SDK,采用离线鉴权方式
|
||||
|
||||
@param v3path v3.bundle 对应的文件路径
|
||||
@param offLinePath offLineBundle.bundle 离线鉴权包路径
|
||||
@param package 密钥数组,必须配置好密钥,SDK 才能正常工作
|
||||
@param size 密钥数组大小
|
||||
@param shouldCreate 如果设置为 YES,我们会在内部创建并持有一个
|
||||
EAGLContext,OpenGL相关操作建议所用OC层接口
|
||||
(注:OC接口会切换到内部创建的EAGLContext上执行,防止多EAGLContext异常问题)
|
||||
@return 第一次鉴权成功后的文件
|
||||
*/
|
||||
|
||||
- (NSData*)setupLocalWithV3Path:(NSString*)v3path
|
||||
offLinePath:(NSString*)offLinePath
|
||||
authPackage:(void*)package
|
||||
authSize:(int)size
|
||||
shouldCreateContext:(BOOL)shouldCreate;
|
||||
|
||||
/**
|
||||
视频处理接口1:
|
||||
- 将 items 中的道具绘制到 pixelBuffer 中
|
||||
|
||||
@param pixelBuffer 图像数据,支持的格式为:BGRA、YUV420SP
|
||||
@param frameid 当前处理的视频帧序数,每次处理完对其进行加 1 操作,不加 1
|
||||
将无法驱动道具中的特效动画
|
||||
@param items 包含多个道具句柄的 int 数组,包括普通道具、美颜道具、手势道具等
|
||||
@param itemCount 句柄数组中包含的句柄个数
|
||||
@return 被处理过的的图像数据,返回 nil 视频处理失败
|
||||
*/
|
||||
- (CVPixelBufferRef)renderPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
withFrameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount;
|
||||
|
||||
/**
|
||||
视频处理接口2:
|
||||
- 将 items 中的道具绘制到 pixelBuffer 中
|
||||
- 与 视频处理接口1 相比新增 flip 参数,将该参数设置为 YES
|
||||
可使道具做水平镜像翻转
|
||||
|
||||
@param pixelBuffer 图像数据,支持的格式为:BGRA、YUV420SP
|
||||
@param frameid 当前处理的视频帧序数,每次处理完对其进行加 1 操作,不加 1
|
||||
将无法驱动道具中的特效动画
|
||||
@param items 包含多个道具句柄的 int 数组
|
||||
@param itemCount 句柄数组中包含的句柄个数
|
||||
@param flip 道具镜像使能,如果设置为 YES 可以将道具做镜像操作
|
||||
@return 被处理过的的图像数据,返回 nil 视频处理失败
|
||||
*/
|
||||
- (CVPixelBufferRef)renderPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
withFrameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount
|
||||
flipx:(BOOL)flip;
|
||||
|
||||
/**
|
||||
视频处理接口3:
|
||||
- 将 items 中的道具绘制到 pixelBuffer 中
|
||||
- 与 视频处理接口2 相比新增 customSize 参数,可以自定义输出分辨率
|
||||
|
||||
@param pixelBuffer 图像数据,支持的格式为:BGRA、YUV420SP
|
||||
@param frameid 当前处理的视频帧序数,每次处理完对其进行加 1 操作,不加 1
|
||||
将无法驱动道具中的特效动画
|
||||
@param items 包含多个道具句柄的 int 数组
|
||||
@param itemCount 句柄数组中包含的句柄个数
|
||||
@param flip 道具镜像使能,如果设置为 YES 可以将道具做镜像操作
|
||||
@param customSize 自定义输出的分辨率,目前仅支持BGRA格式
|
||||
@return 被处理过的的图像数据,返回 nil 视频处理失败
|
||||
*/
|
||||
|
||||
- (CVPixelBufferRef)renderPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
withFrameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount
|
||||
flipx:(BOOL)flip
|
||||
customSize:(CGSize)customSize NS_AVAILABLE_IOS(8_0);
|
||||
|
||||
/**
|
||||
视频处理接口4:
|
||||
- 将 items 中的道具绘制到一个新的 pixelBuffer 中,输出与输入不是同一个
|
||||
pixelBuffer
|
||||
|
||||
@param pixelBuffer 图像数据,支持的格式为:BGRA、YUV420SP
|
||||
@param frameid 当前处理的视频帧序数,每次处理完对其进行加 1 操作,不加 1
|
||||
将无法驱动道具中的特效动画
|
||||
@param items 包含多个道具句柄的 int 数组,包括普通道具、美颜道具、手势道具等
|
||||
@param itemCount 句柄数组中包含的句柄个数
|
||||
@return 被处理过的的图像数据,返回 nil 视频处理失败
|
||||
*/
|
||||
- (CVPixelBufferRef)renderToInternalPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
withFrameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount
|
||||
NS_AVAILABLE_IOS(8_0);
|
||||
|
||||
/**
|
||||
视频处理接口5:
|
||||
- 将 items 中的道具绘制到 textureHandle 及 pixelBuffer 中
|
||||
- 该接口适用于可同时输入 GLES texture 及 pixelBuffer 的用户,这里的
|
||||
pixelBuffer 主要用于 CPU 上的人脸检测,如果只有 GLES texture 此接口将无法工作。
|
||||
|
||||
@param pixelBuffer 图像数据,支持的格式为:BGRA、YUV420SP,用于人脸识别
|
||||
@param textureHandle 用户当前 EAGLContext 下的 textureID,用于图像处理
|
||||
@param frameid 当前处理的视频帧序数,每次处理完对其进行加 1 操作,不加 1
|
||||
将无法驱动道具中的特效动画
|
||||
@param items 包含多个道具句柄的 int 数组,包括普通道具、美颜道具、手势道具等
|
||||
@param itemCount 句柄数组中包含的句柄个数
|
||||
@return 被处理过的的图像数据
|
||||
*/
|
||||
- (FUOutput)renderPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
bgraTexture:(GLuint)textureHandle
|
||||
withFrameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount NS_AVAILABLE_IOS(8_0);
|
||||
|
||||
/**
|
||||
视频处理接口6:
|
||||
- 将items中的道具绘制到 textureHandle 及 pixelBuffer 中
|
||||
- 与 视频处理接口5 相比新增 flip 参数,将该参数设置为 YES
|
||||
可使道具做水平镜像翻转。
|
||||
|
||||
@param pixelBuffer 图像数据,支持的格式为:BGRA、YUV420SP,用于人脸识别
|
||||
@param textureHandle 用户当前 EAGLContext 下的 textureID,用于图像处理
|
||||
@param frameid 当前处理的视频帧序数,每次处理完对其进行加 1 操作,不加 1
|
||||
将无法驱动道具中的特效动画
|
||||
@param items 包含多个道具句柄的int数组,包括普通道具、美颜道具、手势道具等
|
||||
@param itemCount 句柄数组中包含的句柄个数
|
||||
@param flip 道具镜像使能,如果设置为 YES 可以将道具做镜像操作
|
||||
@return 被处理过的的图像数据
|
||||
*/
|
||||
- (FUOutput)renderPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
bgraTexture:(GLuint)textureHandle
|
||||
withFrameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount
|
||||
flipx:(BOOL)flip NS_AVAILABLE_IOS(8_0);
|
||||
|
||||
/**
|
||||
视频处理接口7:
|
||||
- 将items中的道具绘制到 textureHandle 及 pixelBuffer 中
|
||||
- 与 视频处理接口6 相比新增 customSize 参数,可以自定义输出分辨率。
|
||||
|
||||
@param pixelBuffer 图像数据,支持的格式为:BGRA、YUV420SP,用于人脸识别
|
||||
@param textureHandle 用户当前 EAGLContext 下的 textureID,用于图像处理
|
||||
@param frameid 当前处理的视频帧序数,每次处理完对其进行加 1 操作,不加 1
|
||||
将无法驱动道具中的特效动画
|
||||
@param items 包含多个道具句柄的int数组,包括普通道具、美颜道具、手势道具等
|
||||
@param itemCount 句柄数组中包含的句柄个数
|
||||
@param flip 道具镜像使能,如果设置为 YES 可以将道具做镜像操作
|
||||
@param customSize 自定义输出的分辨率,目前仅支持BGRA格式
|
||||
@return 被处理过的的图像数据
|
||||
*/
|
||||
- (FUOutput)renderPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
bgraTexture:(GLuint)textureHandle
|
||||
withFrameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount
|
||||
flipx:(BOOL)flip
|
||||
customSize:(CGSize)customSize NS_AVAILABLE_IOS(8_0);
|
||||
|
||||
/**
|
||||
视频处理接口8:
|
||||
-
|
||||
该接口不包含人脸检测功能,只能对图像做美白、红润、滤镜、磨皮操作,不包含瘦脸及大眼等美型功能。
|
||||
|
||||
@param pixelBuffer 图像数据,支持的格式为:BGRA、YUV420SP
|
||||
@param item 美颜道具句柄
|
||||
@return 被处理过的的图像数据 返回 nil 视频处理失败
|
||||
*/
|
||||
- (CVPixelBufferRef)beautifyPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
withBeautyItem:(int)item;
|
||||
|
||||
/**
|
||||
视频处理接口9:
|
||||
- 将 items 中的道具绘制到 YUV420P 图像中
|
||||
|
||||
@param y Y帧图像地址
|
||||
@param u U帧图像地址
|
||||
@param v V帧图像地址
|
||||
@param ystride Y帧stride
|
||||
@param ustride U帧stride
|
||||
@param vstride V帧stride
|
||||
@param width 图像宽度
|
||||
@param height 图像高度
|
||||
@param frameid 当前处理的视频帧序数,每次处理完对其进行加 1 操作,不加 1
|
||||
将无法驱动道具中的特效动画
|
||||
@param items 包含多个道具句柄的 int 数组,包括普通道具、美颜道具、手势道具等
|
||||
@param itemCount 句柄数组中包含的句柄个数
|
||||
*/
|
||||
- (void)renderFrame:(uint8_t*)y
|
||||
u:(uint8_t*)u
|
||||
v:(uint8_t*)v
|
||||
ystride:(int)ystride
|
||||
ustride:(int)ustride
|
||||
vstride:(int)vstride
|
||||
width:(int)width
|
||||
height:(int)height
|
||||
frameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount;
|
||||
|
||||
/**
|
||||
视频处理接口10:
|
||||
- 将 items 中的道具绘制到 YUV420P 图像中
|
||||
- 与 视频处理接口9 相比新增 flip 参数,将该参数设置为 YES
|
||||
可使道具做水平镜像翻转
|
||||
|
||||
@param y Y帧图像地址
|
||||
@param u U帧图像地址
|
||||
@param v V帧图像地址
|
||||
@param ystride Y帧stride
|
||||
@param ustride U帧stride
|
||||
@param vstride V帧stride
|
||||
@param width 图像宽度
|
||||
@param height 图像高度
|
||||
@param frameid 当前处理的视频帧序数,每次处理完对其进行加 1 操作,不加 1
|
||||
将无法驱动道具中的特效动画
|
||||
@param items 包含多个道具句柄的 int 数组,包括普通道具、美颜道具、手势道具等
|
||||
@param itemCount 句柄数组中包含的句柄个数
|
||||
@param flip 道具镜像使能,如果设置为 YES 可以将道具做镜像操作
|
||||
*/
|
||||
- (void)renderFrame:(uint8_t*)y
|
||||
u:(uint8_t*)u
|
||||
v:(uint8_t*)v
|
||||
ystride:(int)ystride
|
||||
ustride:(int)ustride
|
||||
vstride:(int)vstride
|
||||
width:(int)width
|
||||
height:(int)height
|
||||
frameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount
|
||||
flipx:(BOOL)flip;
|
||||
|
||||
/**
|
||||
视频处理接口11:
|
||||
- 将 items 中的道具绘制到 pixelBuffer 中
|
||||
- 与 视频处理接口2 相比新增 masks 参数,用来指定 items
|
||||
中的道具画在多人中的哪一张脸上
|
||||
|
||||
@param pixelBuffer 图像数据,支持的格式为:BGRA、YUV420SP
|
||||
@param frameid 当前处理的视频帧序数,每次处理完对其进行加 1 操作,不加 1
|
||||
将无法驱动道具中的特效动画
|
||||
@param items 包含多个道具句柄的 int 数组
|
||||
@param itemCount 句柄数组中包含的句柄个数
|
||||
@param flip 道具镜像使能,如果设置为 YES 可以将道具做镜像操作
|
||||
@param masks 指定items中的道具画在多张人脸中的哪一张脸上的 int 数组,其长度要与
|
||||
items 长度一致,
|
||||
masks中的每一位与items中的每一位道具一一对应。使用方法为:要使某一个道具画在检测到的第一张人脸上,
|
||||
对应的int值为 "2的0次方",画在第二张人脸上对应的int值为
|
||||
“2的1次方”,第三张人脸对应的int值为 “2的2次方”, 以此类推。例:masks =
|
||||
{pow(2,0),pow(2,1),pow(2,2)....},值得注意的是美颜道具对应的int值为 0。
|
||||
@return 被处理过的的图像数据,返回 nil 视频处理失败
|
||||
*/
|
||||
- (CVPixelBufferRef)renderPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
withFrameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount
|
||||
flipx:(BOOL)flip
|
||||
masks:(void*)masks;
|
||||
|
||||
/**
|
||||
视频处理接口12: 注意:目前仅支持背景分割场景
|
||||
- 将 items 中的道具绘制到 pixelBuffer 中
|
||||
- 与 视频处理接口2 相比新增 customSize 参数,可以自定义输出分辨率
|
||||
|
||||
@param pixelBuffer 图像数据,支持的格式为:BGRA、YUV420SP
|
||||
@param frameid 当前处理的视频帧序数,每次处理完对其进行加 1 操作,不加 1
|
||||
将无法驱动道具中的特效动画
|
||||
@param items 包含多个道具句柄的 int 数组
|
||||
@param itemCount 句柄数组中包含的句柄个数
|
||||
@param flip 道具镜像使能,如果设置为 YES 可以将道具做镜像操作
|
||||
@param customSize 自定义输出的分辨率,目前仅支持BGRA格式
|
||||
@param useAlpha 是否带道具透明通道,if useAlpha = NO,RGBA 数据alpha
|
||||
会被强制设置为1,其他视频处理接口皆为该模式
|
||||
@return 被处理过的的图像数据,返回 nil 视频处理失败
|
||||
*/
|
||||
- (CVPixelBufferRef)renderPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
withFrameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount
|
||||
flipx:(BOOL)flip
|
||||
customSize:(CGSize)customSize
|
||||
useAlpha:(BOOL)useAlpha;
|
||||
|
||||
- (int)renderItems:(void*)inPtr
|
||||
inFormat:(FUFormat)inFormat
|
||||
outPtr:(void*)outPtr
|
||||
outFormat:(FUFormat)outFormat
|
||||
width:(int)width
|
||||
height:(int)height
|
||||
frameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount
|
||||
flipx:(BOOL)flip;
|
||||
|
||||
- (int)renderBundles:(void*)inPtr
|
||||
inFormat:(FUFormat)inFormat
|
||||
outPtr:(void*)outPtr
|
||||
outFormat:(FUFormat)outFormat
|
||||
width:(int)width
|
||||
height:(int)height
|
||||
frameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount;
|
||||
|
||||
- (int)renderBundlesSplitView:(void*)inPtr
|
||||
inFormat:(FUFormat)inFormat
|
||||
outPtr:(void*)outPtr
|
||||
outFormat:(FUFormat)outFormat
|
||||
width:(int)width
|
||||
height:(int)height
|
||||
frameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount
|
||||
splitViewInfoPtr:(TSplitViewInfo*)splitViewInfoPtr;
|
||||
|
||||
- (CVPixelBufferRef)renderBundlesWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
withFrameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount;
|
||||
|
||||
- (CVPixelBufferRef)
|
||||
renderBundlesSplitViewWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
withFrameId:(int)frameid
|
||||
items:(int*)items
|
||||
itemCount:(int)itemCount
|
||||
splitViewInfoPtr:(TSplitViewInfo*)splitViewInfoPtr;
|
||||
|
||||
- (void)setInputCameraMatrix:(int)flip_x
|
||||
flip_y:(int)flip_y
|
||||
rotate_mode:(int)rotate_mode;
|
||||
|
||||
- (void)setOutputResolution:(int)w h:(int)h;
|
||||
|
||||
/*
|
||||
@return 1代表成功,0代表失败
|
||||
*/
|
||||
- (int)rotateImage:(FURotatedImage*)outImage
|
||||
inPtr:(void*)inPtr
|
||||
inFormat:(FUFormat)inFormat
|
||||
width:(int)width
|
||||
height:(int)height
|
||||
rotationMode:(FURotationMode)rotationMode
|
||||
flipX:(BOOL)flipX
|
||||
flipY:(BOOL)flipY;
|
||||
|
||||
/**
|
||||
resize视频图像,目前仅支持BGRA格式的pixelBuffer
|
||||
|
||||
@param pixelBuffer BGRA格式的pixelBuffer
|
||||
@param resizeSize resizeSize
|
||||
@return resizeSize之后的pixelBuffer
|
||||
*/
|
||||
- (CVPixelBufferRef)resizePixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
resizeSize:(CGSize)resizeSize NS_AVAILABLE_IOS(8_0);
|
||||
|
||||
/**
|
||||
通过texture获取指定大小与格式的pixelBuffer
|
||||
|
||||
@param texture rgba texture
|
||||
@param textureSize texture 尺寸
|
||||
@param outPutSize 输出的pixelBuffer的尺寸
|
||||
@param outputFormat
|
||||
输出的pixelBuffer的格式,接受的参数有两个,分别为:FU_FORMAT_NV12_BUFFER、FU_FORMAT_BGRA_BUFFER
|
||||
@return 从texture获取到的指定大小与格式的pixelBuffer
|
||||
*/
|
||||
- (CVPixelBufferRef)getPixelBufferFromTexture:(int)texture
|
||||
textureSize:(CGSize)textureSize
|
||||
outputSize:(CGSize)outPutSize
|
||||
outputFormat:(int)outputFormat
|
||||
NS_AVAILABLE_IOS(8_0);
|
||||
|
||||
/**
|
||||
切换摄像头时需调用的接口:
|
||||
- 切换摄像头时需要调用该接口,我们会在内部重置人脸检测的一些状态
|
||||
*/
|
||||
+ (void)onCameraChange;
|
||||
|
||||
/**
|
||||
销毁所有gl资源时需调用的接口:
|
||||
- 销毁所有gl资源时需要调用该接口
|
||||
*/
|
||||
+ (void)ReleaseGLResources;
|
||||
|
||||
/**
|
||||
销毁所有道具时需调用的接口:
|
||||
- 销毁所有道具时需要调用该接口,我们会在内部销毁每个指令中的OpenGL资源
|
||||
*/
|
||||
+ (void)OnDeviceLost;
|
||||
|
||||
/**
|
||||
销毁所有道具时需调用的接口:
|
||||
- 销毁所有道具时需要调用该接口,我们仅销毁Cpu资源
|
||||
*/
|
||||
+ (void)OnDeviceLostSafe;
|
||||
|
||||
/**
|
||||
通过道具二进制文件创建道具:
|
||||
- 通过道具二进制文件创建道具句柄
|
||||
|
||||
@param data 道具二进制文件
|
||||
@param size 文件大小
|
||||
@return 创建的道具句柄
|
||||
*/
|
||||
+ (int)createItemFromPackage:(void*)data size:(int)size;
|
||||
|
||||
/**
|
||||
通过道具文件路径创建道具:
|
||||
- 通过道具文件路径创建道具句柄
|
||||
|
||||
@param path 道具文件路径
|
||||
@return 创建的道具句柄
|
||||
*/
|
||||
+ (int)itemWithContentsOfFile:(NSString*)path;
|
||||
|
||||
/**
|
||||
销毁单个道具:
|
||||
- 通过道具句柄销毁道具,并释放相关资源
|
||||
- 销毁道具后请将道具句柄设为 0 ,以避免 SDK 使用无效的句柄而导致程序出错。
|
||||
|
||||
@param item 道具句柄
|
||||
*/
|
||||
+ (void)destroyItem:(int)item;
|
||||
|
||||
/**
|
||||
销毁所有道具:
|
||||
- 销毁全部道具,并释放相关资源
|
||||
- 销毁道具后请将道具句柄数组中的句柄设为 0 ,以避免 SDK
|
||||
使用无效的句柄而导致程序出错。
|
||||
*/
|
||||
+ (void)destroyAllItems;
|
||||
|
||||
/**
|
||||
加载AI能力模型bundle
|
||||
@param data AI能力模型二进制文件
|
||||
@param size 文件大小
|
||||
@param type AI能力类型,定义在FUAITYPE中
|
||||
@return 加载成功返回1,否则返回0
|
||||
*/
|
||||
+ (int)loadAIModelFromPackage:(void*)data size:(int)size aitype:(FUAITYPE)type;
|
||||
|
||||
/**
|
||||
在不需要的时候,释放AI能力模型bundle
|
||||
@param type AI能力类型,定义在FUAITYPE中
|
||||
@return 释放成功返回1,否则返回0
|
||||
*/
|
||||
+ (int)releaseAIModel:(FUAITYPE)type;
|
||||
|
||||
/**
|
||||
获取AI能力模型是否加载。
|
||||
@param type AI能力类型,定义在FUAITYPE中
|
||||
@return 已加载返回1,否则返回0
|
||||
*/
|
||||
+ (int)isAIModelLoaded:(FUAITYPE)type;
|
||||
|
||||
/**
|
||||
为道具设置参数:
|
||||
|
||||
@param item 道具句柄
|
||||
@param name 参数名
|
||||
@param value 参数值:只支持 NSString 、 NSNumber 两种数据类型
|
||||
@return 执行结果:返回 0 代表设置失败,大于 0 表示设置成功
|
||||
*/
|
||||
+ (int)itemSetParam:(int)item withName:(NSString*)name value:(id)value;
|
||||
|
||||
/**
|
||||
为道具设置参数:
|
||||
|
||||
@param item 道具句柄
|
||||
@param name 参数名
|
||||
@param value 参数值:double 数组
|
||||
@param length 参数值:double 数组长度
|
||||
@return 执行结果:返回 0 代表设置失败,大于 0 表示设置成功
|
||||
*/
|
||||
+ (int)itemSetParamdv:(int)item
|
||||
withName:(NSString*)name
|
||||
value:(double*)value
|
||||
length:(int)length;
|
||||
|
||||
/**
|
||||
从道具中获取 double 数组:
|
||||
|
||||
@param item 道具句柄
|
||||
@param name 参数名
|
||||
@param value 参数值:double 数组
|
||||
@param length 参数值:double 数组长度
|
||||
@return 执行结果:返回获取的数组长度
|
||||
*/
|
||||
+ (int)itemGetParamdv:(int)item
|
||||
withName:(NSString*)name
|
||||
buffer:(double*)buffer
|
||||
length:(int)length;
|
||||
/**
|
||||
从道具中获取 float 数组:
|
||||
|
||||
@param item 道具句柄
|
||||
@param name 参数名
|
||||
@param value 参数值:float 数组
|
||||
@param length 参数值:float 数组长度
|
||||
@return 执行结果:返回获取的数组长度
|
||||
*/
|
||||
+ (int)itemGetParamfv:(int)item
|
||||
withName:(NSString*)name
|
||||
buffer:(float*)buffer
|
||||
length:(int)length;
|
||||
|
||||
/**
|
||||
从道具中获取 double 型参数值:
|
||||
|
||||
@param item 道具句柄
|
||||
@param name 参数名
|
||||
@return 参数值
|
||||
*/
|
||||
+ (double)getDoubleParamFromItem:(int)item withName:(NSString*)name;
|
||||
|
||||
/**
|
||||
从道具中获取 NSString 型参数值:
|
||||
|
||||
@param item 道具句柄
|
||||
@param name 参数名
|
||||
@return 参数值
|
||||
*/
|
||||
+ (NSString*)getStringParamFromItem:(int)item withName:(NSString*)name;
|
||||
|
||||
+ (int)itemSetParamu8v:(int)item
|
||||
withName:(NSString*)name
|
||||
buffer:(void*)buffer
|
||||
size:(int)size;
|
||||
|
||||
+ (int)itemGetParamu8v:(int)item
|
||||
withName:(NSString*)name
|
||||
buffer:(void*)buffer
|
||||
size:(int)size;
|
||||
|
||||
+ (int)itemSetParamu64:(int)item
|
||||
withName:(NSString*)name
|
||||
value:(unsigned long long)value;
|
||||
/**
|
||||
判断是否检测到人脸:
|
||||
|
||||
@return 检测到的人脸个数,返回 0 代表没有检测到人脸
|
||||
*/
|
||||
+ (int)isTracking;
|
||||
|
||||
/**
|
||||
判断SDK是否已经初始化:
|
||||
|
||||
@return 返回1代表初始化,返回0代表未初始化
|
||||
*/
|
||||
+ (int)isLibraryInit;
|
||||
|
||||
/**
|
||||
开启多人检测模式:
|
||||
- 开启多人检测模式,最多可同时检测 8 张人脸
|
||||
|
||||
@param maxFaces 设置多人模式开启的人脸个数,最多支持 8 个
|
||||
@return 上一次设置的人脸个数
|
||||
*/
|
||||
+ (int)setMaxFaces:(int)maxFaces;
|
||||
|
||||
/**
|
||||
人脸信息跟踪:
|
||||
- 该接口只对人脸进行检测,如果程序中没有运行过视频处理接口( 视频处理接口8
|
||||
除外),则需要先执行完该接口才能使用 获取人脸信息接口 来获取人脸信息
|
||||
|
||||
@param inputFormat 输入图像格式:FU_FORMAT_BGRA_BUFFER 或 FU_FORMAT_NV12_BUFFER
|
||||
@param inputData 输入的图像 bytes 地址
|
||||
@param width 图像宽度
|
||||
@param height 图像高度
|
||||
@return 检测到的人脸个数,返回 0 代表没有检测到人脸
|
||||
*/
|
||||
+ (int)trackFace:(int)inputFormat
|
||||
inputData:(void*)inputData
|
||||
width:(int)width
|
||||
height:(int)height;
|
||||
|
||||
+ (int)trackFaceWithTongue:(int)inputFormat
|
||||
inputData:(void*)inputData
|
||||
width:(int)width
|
||||
height:(int)height;
|
||||
|
||||
/**
|
||||
获取人脸信息:
|
||||
- 在程序中需要先运行过视频处理接口( 视频处理接口8 除外)或 人脸信息跟踪接口
|
||||
后才能使用该接口来获取人脸信息;
|
||||
-
|
||||
该接口能获取到的人脸信息与我司颁发的证书有关,普通证书无法通过该接口获取到人脸信息;
|
||||
- 具体参数及证书要求如下:
|
||||
|
||||
landmarks: 2D人脸特征点,返回值为75个二维坐标,长度75*2
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
landmarks_ar: 3D人脸特征点,返回值为75个三维坐标,长度75*3
|
||||
证书要求: AVATAR证书
|
||||
|
||||
rotation: 人脸三维旋转,返回值为旋转四元数,长度4
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
translation: 人脸三维位移,返回值一个三维向量,长度3
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
eye_rotation: 眼球旋转,返回值为旋转四元数,长度4
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
rotation_raw: 人脸三维旋转(不考虑屏幕方向),返回值为旋转四元数,长度4
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
expression: 表情系数,长度46
|
||||
证书要求: AVATAR证书
|
||||
|
||||
projection_matrix: 投影矩阵,长度16
|
||||
证书要求: AVATAR证书
|
||||
|
||||
face_rect: 人脸矩形框,返回值为(xmin,ymin,xmax,ymax),长度4
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
rotation_mode: 人脸朝向,0-3分别对应手机四种朝向,长度1
|
||||
证书要求: LANDMARK证书、AVATAR证书
|
||||
|
||||
@param faceId 被检测的人脸 ID ,未开启多人检测时传 0
|
||||
,表示检测第一个人的人脸信息;当开启多人检测时,其取值范围为 [0 ~ maxFaces-1]
|
||||
,取其中第几个值就代表检测第几个人的人脸信息
|
||||
@param name 人脸信息参数名: "landmarks" , "eye_rotation" , "translation" ,
|
||||
"rotation" ....
|
||||
@param pret 作为容器使用的 float 数组指针,获取到的人脸信息会被直接写入该 float
|
||||
数组。
|
||||
@param number float 数组的长度
|
||||
@return 返回 1 代表获取成功,返回 0 代表获取失败
|
||||
*/
|
||||
+ (int)getFaceInfo:(int)faceId
|
||||
name:(NSString*)name
|
||||
pret:(float*)pret
|
||||
number:(int)number;
|
||||
|
||||
+ (int)getFaceInfoRotated:(int)faceId
|
||||
name:(NSString*)name
|
||||
pret:(float*)pret
|
||||
number:(int)number;
|
||||
|
||||
/**
|
||||
获取正在跟踪人脸的标识符,用于在SDK外部对多人情况下的不同人脸进行区别。
|
||||
@param faceId,人脸编号,表示识别到的第 x
|
||||
张人脸,从0开始,到n-1,n为当前跟踪到的人脸数。
|
||||
@return 人脸的标识符 [1,maxFaces]
|
||||
*/
|
||||
+ (int)getFaceIdentifier:(int)faceId;
|
||||
|
||||
/**
|
||||
将普通道具绑定到avatar道具:
|
||||
- 该接口主要应用于 P2A 项目中,将普通道具绑定到 avatar
|
||||
道具上,从而实现道具间的数据共享;
|
||||
- 在视频处理时只需要传入 avatar 道具句柄,普通道具也会和 avatar
|
||||
一起被绘制出来。
|
||||
- 普通道具又分免费版和收费版,免费版有免费版对应的 contract
|
||||
文件,收费版有收费版对应的 contract 文件,当绑定时需要同时传入这些 contracts
|
||||
文件才能绑定成功。
|
||||
- 注意: contract 的创建和普通道具创建方法一致
|
||||
|
||||
@param avatarItem avatar 道具句柄
|
||||
@param items 需要被绑定到 avatar 道具上的普通道具的句柄数组
|
||||
@param itemsCount 句柄数组包含的道具句柄个数
|
||||
@param contracts contract 道具的句柄数组
|
||||
@param contractsCount contracts 数组中 contract 道具句柄的个数
|
||||
@return 被绑定到 avatar 道具上的普通道具个数
|
||||
*/
|
||||
+ (int)avatarBindItems:(int)avatarItem
|
||||
items:(int*)items
|
||||
itemsCount:(int)itemsCount
|
||||
contracts:(int*)contracts
|
||||
contractsCount:(int)contractsCount
|
||||
DEPRECATED_MSG_ATTRIBUTE("use bindItems:items:itemsCount: instead");
|
||||
|
||||
/**
|
||||
将普通道具从avatar道具上解绑:
|
||||
- 该接口可以将普通道具从 avatar
|
||||
道具上解绑,主要应用场景为切换道具或去掉某个道具
|
||||
|
||||
@param avatarItem avatar 道具句柄
|
||||
@param items 需要从 avatar 道具上的解除绑定的普通道具的句柄数组
|
||||
@param itemsCount 句柄数组包含的道具句柄个数
|
||||
@return 从 avatar 道具上解除绑定的普通道具个数
|
||||
*/
|
||||
+ (int)avatarUnbindItems:(int)avatarItem
|
||||
items:(int*)items
|
||||
itemsCount:(int)itemsCount
|
||||
DEPRECATED_MSG_ATTRIBUTE("use unBindItems:items:itemsCount: instead");
|
||||
|
||||
/**
|
||||
绑定道具:
|
||||
-
|
||||
该接口可以将一些普通道具绑定到某个目标道具上,从而实现道具间的数据共享,在视频处理时只需要传入该目标道具句柄即可
|
||||
|
||||
@param item 目标道具句柄
|
||||
@param items 需要被绑定到目标道具上的其他道具的句柄数组
|
||||
@param itemsCount 句柄数组包含的道具句柄个数
|
||||
@return 被绑定到目标道具上的普通道具个数
|
||||
*/
|
||||
+ (int)bindItems:(int)item items:(int*)items itemsCount:(int)itemsCount;
|
||||
|
||||
/**
|
||||
解绑道具:
|
||||
- 该接口可以将一些普通道具从某个目标道具上解绑
|
||||
|
||||
@param item 目标道具句柄
|
||||
@param items 需要从目标道具上解除绑定的普通道具的句柄数组
|
||||
@param itemsCount 句柄数组包含的道具句柄个数
|
||||
@return 被绑定到目标道具上的普通道具个数
|
||||
*/
|
||||
+ (int)unBindItems:(int)item items:(int*)items itemsCount:(int)itemsCount;
|
||||
|
||||
/**
|
||||
解绑所有道具:
|
||||
- 该接口可以解绑绑定在目标道具上的全部道具
|
||||
|
||||
@param item 目标道具句柄
|
||||
@return 从目标道具上解除绑定的普通道具个数
|
||||
*/
|
||||
+ (int)unbindAllItems:(int)item;
|
||||
|
||||
/**
|
||||
获取 SDK 版本信息:
|
||||
|
||||
@return 版本信息
|
||||
*/
|
||||
+ (NSString*)getVersion;
|
||||
|
||||
+ (void)setDefaultRotationMode:(int)mode;
|
||||
|
||||
+ (void)setDeviceOrientation:(int)orientation;
|
||||
|
||||
+ (int)getCurrentRotationMode;
|
||||
|
||||
+ (int)setMultiSamples:(int)samples;
|
||||
|
||||
+ (void)setAsyncTrackFaceEnable:(int)enable;
|
||||
|
||||
+ (void)setTongueTrackingEnable:(int)enable;
|
||||
|
||||
+ (int)loadTongueModel:(void*)model size:(int)size;
|
||||
|
||||
+ (int)SetLoadQuality:(int)quality;
|
||||
/**
|
||||
统计接口调用次数
|
||||
@param 接口名称
|
||||
@return 返回 1 代表调用成功,返回 0 代表代表失败
|
||||
**/
|
||||
+ (int)authCountWithAPIName:(NSString*)name;
|
||||
|
||||
/**
|
||||
释放nama资源
|
||||
*/
|
||||
+ (void)namaLibDestroy;
|
||||
|
||||
+ (void)humanProcessorReset;
|
||||
|
||||
/**
|
||||
prepare GL resource for a list of items in advance
|
||||
This function needs a GLES 2.0+ context.
|
||||
@param items the list of items
|
||||
@param itemCount the number of items
|
||||
*/
|
||||
- (void)prepareGLResource:items:(int*)items itemCount:(int)itemCount;
|
||||
|
||||
/**
|
||||
check prepare gl resource is ready.
|
||||
1 for ready prepared, 0 false.
|
||||
@param items the list of items
|
||||
@param itemCount the number of items
|
||||
*/
|
||||
- (int)isGLPrepared:items:(int*)items itemCount:(int)itemCount;
|
||||
|
||||
/**
|
||||
check gl error
|
||||
@return OpenGL error information, 0 for no error
|
||||
*/
|
||||
+ (int)checkGLError;
|
||||
|
||||
@end
|
||||
179
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUScene.h
Executable file
179
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUScene.h
Executable file
@@ -0,0 +1,179 @@
|
||||
//
|
||||
// FUScene.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/16.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUBackground.h"
|
||||
#import "FUCustomBackground.h"
|
||||
#import "FULight.h"
|
||||
#import "FUSceneCamera.h"
|
||||
#import "FUAvatar.h"
|
||||
#import "FUCameraAnimation.h"
|
||||
#import "FUAIConfig.h"
|
||||
#import "FURenderableObject.h"
|
||||
|
||||
@class FUScene;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef enum : NSUInteger {
|
||||
FUProjectionModePerspective,
|
||||
FUProjectionModeParallel,
|
||||
} FUProjectionMode;
|
||||
|
||||
@protocol FUSceneDelegate <NSObject>
|
||||
|
||||
- (void)scene:(FUScene *)scene AIConfigDidUpdate:(FUAIConfig *)AIConfig;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface FUScene : FURenderableObject
|
||||
|
||||
@property (nonatomic, weak) id<FUSceneDelegate> delegate;
|
||||
|
||||
/// controller_config.bundle 文件路径,默认为 FURenderKit 初始化时设置的 controller_config 路径,用户可以通过修改该参数修改该路径。
|
||||
@property (nonatomic, copy, readonly) NSString *controllerConfigPath;
|
||||
|
||||
/// 背景道具
|
||||
@property (nonatomic, strong) FUBackground *background;
|
||||
|
||||
/// 背景颜色,如果设置了背景颜色,背景道具自动失效
|
||||
@property (nonatomic, strong) UIColor *backgroundColor;
|
||||
|
||||
/// 机位道具
|
||||
@property (nonatomic, strong) FUSceneCamera *sceneCamera;
|
||||
|
||||
/// 是否使用 orthogonal projection, 默认为 perspective projection
|
||||
@property (nonatomic, assign) BOOL enableOrthogonalProjection;
|
||||
|
||||
@property (nonatomic, assign) float renderFov;
|
||||
|
||||
@property (nonatomic, assign) float renderOrthSize;
|
||||
|
||||
@property (nonatomic, assign) double znear;
|
||||
|
||||
@property (nonatomic, assign) double zfar;
|
||||
|
||||
/// 光照道具
|
||||
@property (nonatomic, strong) FULight *light;
|
||||
|
||||
@property (nonatomic, assign) BOOL enableLowQualityLighting;
|
||||
|
||||
@property (nonatomic, assign) BOOL enableBloom;
|
||||
|
||||
/// 阴影开关
|
||||
@property (nonatomic, assign) BOOL enableShadow;
|
||||
|
||||
@property (nonatomic, assign) BOOL enableRenderCameraImage;
|
||||
|
||||
@property (nonatomic, copy, readonly) NSArray<FUAvatar *> *avatars;
|
||||
|
||||
- (FUScene *)initWithControllerConfigPath:(NSString *)controllerConfigPath;
|
||||
|
||||
- (FUScene *)initWithControllerConfigPath:(NSString *)controllerConfigPath litemListJson:(NSString *)litemListJson;
|
||||
|
||||
#pragma mark - Avatar
|
||||
|
||||
- (BOOL)addAvatar:(FUAvatar *)avatar;
|
||||
|
||||
- (void)addAvatar:(FUAvatar *)avatar completion:(void(^)(BOOL result))completion;
|
||||
|
||||
- (void)removeAvatar:(FUAvatar *)avatar;
|
||||
|
||||
- (void)removeAvatar:(FUAvatar *)avatar completion:(void(^)(void))completion;
|
||||
|
||||
- (BOOL)replaceAvatar:(FUAvatar *)avatar withNewAvatar:(FUAvatar *)newAvatar;
|
||||
|
||||
- (void)replaceAvatar:(FUAvatar *)avatar withNewAvatar:(FUAvatar *)newAvatar compoletion:(void(^)(BOOL result))completion;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUScene (AIConfig)
|
||||
|
||||
@property (nonatomic, strong, readonly) FUAIConfig *AIConfig;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUScene (Animation)
|
||||
|
||||
@property (nonatomic, assign) BOOL enableCustomAnimationTime;
|
||||
|
||||
@property (nonatomic, assign) float customAnimationTime;
|
||||
|
||||
@property (nonatomic, assign) BOOL pauseSystemTimeUpdate;
|
||||
|
||||
@property (nonatomic, assign) BOOL enableCameraAnimation;
|
||||
|
||||
@property (nonatomic, assign) BOOL enableCameraAnimationLerp;
|
||||
|
||||
/// 相机动画列表
|
||||
@property (nonatomic, copy, readonly) NSArray<FUCameraAnimation *> *cameraAnimations;
|
||||
/// 当前正在播放的相机动画
|
||||
@property (nonatomic, strong, readonly) FUCameraAnimation *currentCameraAnimation;
|
||||
|
||||
/// 添加动画,如果相机动画的 name 不为空,可以通过 name 查找或移除相机动画
|
||||
/// @param cameraAnimation 动画
|
||||
- (void)addCameraAnimation:(FUCameraAnimation *)cameraAnimation;
|
||||
|
||||
/// 通过动画名称查找相机动画
|
||||
/// @param cameraAnimationName 相机动画名称
|
||||
- (FUCameraAnimation *)cameraAnimationForName:(NSString *)cameraAnimationName;
|
||||
|
||||
/// 移除相机动画
|
||||
/// @param cameraAnimation 相机动画
|
||||
- (void)removeCameraAnimation:(FUCameraAnimation *)cameraAnimation;
|
||||
|
||||
/// 通过名称移除相机动画
|
||||
/// @param cameraAnimationName 相机动画名称
|
||||
- (void)removeCameraAnimationWithName:(NSString *)cameraAnimationName;
|
||||
|
||||
/// 播放相机动画
|
||||
/// @param cameraAnimation 相机动画
|
||||
/// @param playOnce YES 只播放一次,NO 循环播放
|
||||
/// @param transitionDuration 相机动画过度时间
|
||||
- (void)playCameraAnimation:(nullable FUCameraAnimation *)cameraAnimation playOnce:(BOOL)playOnce transitionDuration:(float)transitionDuration;
|
||||
|
||||
/// 通过名称播放相机动画
|
||||
/// @param cameraAnimationName 相机动画名称
|
||||
/// @param playOnce YES 只播放一次,NO 循环播放
|
||||
/// @param transitionDuration 相机动画过度时间
|
||||
- (void)playCameraAnimationWithName:(NSString *)cameraAnimationName playOnce:(BOOL)playOnce transitionDuration:(float)transitionDuration;
|
||||
|
||||
- (void)pauseCurrentCameraAnimation;
|
||||
|
||||
- (void)resumeCurrentCameraAnimation;
|
||||
|
||||
- (void)resetCurrentCameraAnimation;
|
||||
|
||||
- (float)getProgressForCameraAnimation:(FUCameraAnimation *)cameraAnimation;
|
||||
|
||||
- (float)getCurrentCameraAnimationTransitionProgress;
|
||||
|
||||
- (int)getFrameNumberForCameraAnimation:(FUCameraAnimation *)cameraAnimation;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUScene (DynamicBone)
|
||||
|
||||
@property (nonatomic, assign) BOOL enableDynamicbone;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUScene (Reflection)
|
||||
|
||||
/// 是否开启倒影(默认为 YES)
|
||||
@property (nonatomic, assign) BOOL enableReflection;
|
||||
|
||||
/// 设置倒影参数
|
||||
/// @param transparency 倒影透明度 (0~1)
|
||||
/// @param distance 倒影显示距离
|
||||
/// (说明:倒影显示距离与倒影透明度的设置要合理搭配才能出来比较好的效果,两者呈正相关的关系)
|
||||
- (BOOL)reflectionWithTransparency:(float)transparency distance:(float)distance;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// FUAvatarCamera.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/16.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUSceneCamera : FUItem
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// FUSerialQueue.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by liuyang on 2021/9/1.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUSerialQueue : NSObject
|
||||
|
||||
+ (instancetype)queueWithLabel:(NSString *)label;
|
||||
|
||||
- (void)sync:(dispatch_block_t)block;
|
||||
|
||||
- (void)async:(dispatch_block_t)block;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// FUSetupConfig.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by liuyang on 2020/12/30.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUStruct.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUSetupConfig : NSObject
|
||||
|
||||
@property (nonatomic, assign) FUAuthPack authPack;
|
||||
|
||||
@property (nonatomic, copy) NSString *controllerPath;
|
||||
|
||||
@property (nonatomic, assign) BOOL enableCacheSceneShaderProgram;
|
||||
|
||||
@property (nonatomic, copy) NSString *controllerConfigPath;
|
||||
|
||||
//离线鉴权包路径
|
||||
@property (nonatomic, copy) NSString *offLinePath;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
19
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUSticker.h
Executable file
19
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUSticker.h
Executable file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// FUStagePropItem.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/12.
|
||||
//
|
||||
|
||||
#import "FUItem.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
/**
|
||||
* 无特殊设置项的道具直接使用此类实例化
|
||||
* 包含 道具贴纸, AR面具、搞笑大头、表情识别、哈哈镜
|
||||
*/
|
||||
@interface FUSticker : FUItem
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// FUStickerContainer.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Chen on 2021/1/18.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUSticker.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
/**
|
||||
* 可叠加的道具可以放到这里
|
||||
*/
|
||||
@interface FUStickerContainer : NSObject
|
||||
/**
|
||||
* 添加 sticker,移除当前已经加载的所有 sticker
|
||||
* flag: YES 移除,NO 叠加(不移除)
|
||||
*/
|
||||
//- (void)addSticker:(FUSticker *)item removeCurrent:(BOOL)flag;
|
||||
/**
|
||||
* 单个FUSticker操作接口
|
||||
* 内部已经加锁,外部无需处理
|
||||
*/
|
||||
- (void)addSticker:(FUSticker *)sticker completion:(nullable void(^)(void))completion;
|
||||
- (void)removeSticker:(FUSticker *)sticker completion:(nullable void(^)(void))completion;
|
||||
//- (void)updateSticker:(FUSticker *)item;
|
||||
//按照路径移除
|
||||
- (void)removeStickerForPath:(NSString *)stickerPath completion:(nullable void(^)(void))completion;
|
||||
|
||||
- (void)replaceSticker:(FUSticker *)oldSticker withSticker:(FUSticker *)newSticker completion:(nullable void(^)(void))completion;
|
||||
|
||||
/**
|
||||
* 多个FUSticker操作接口
|
||||
* 内部已经加锁,外部无需处理
|
||||
*/
|
||||
- (void)addStickers:(NSArray <FUSticker *> *)stickers completion:(nullable void(^)(void))completion;
|
||||
- (void)removeStickers:(NSArray <FUSticker *> *)stickers completion:(nullable void(^)(void))completion;
|
||||
//- (void)updateStickers:(NSArray <FUSticker *> *)items;
|
||||
- (void)removeStickersForPaths:(NSArray <NSString *> *)stickerPaths completion:(nullable void(^)(void))completion;
|
||||
/**
|
||||
* 移除所有已经添加的FUSticker
|
||||
* 内部已经枷锁,外部无序需处理
|
||||
*/
|
||||
- (void)removeAllSticks;
|
||||
- (NSArray *)allStickers;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
159
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUStruct.h
Executable file
159
Example/SellyCloudSDK/Live/Beauty/FURenderKit.framework/Headers/FUStruct.h
Executable file
@@ -0,0 +1,159 @@
|
||||
//
|
||||
// FUPosition.h
|
||||
// FUAvatarSDK
|
||||
//
|
||||
// Created by ly-Mac on 2020/11/24.
|
||||
//
|
||||
#import <UIKit/UIKit.h>
|
||||
/* Definition of `FU_EXTERN'. */
|
||||
|
||||
#if !defined(FU_EXTERN)
|
||||
# if defined(__cplusplus)
|
||||
# define FU_EXTERN extern "C" __attribute__((visibility("default")))
|
||||
# else
|
||||
# define FU_EXTERN extern __attribute__((visibility("default")))
|
||||
# endif
|
||||
#endif /* !defined(FU_EXTERN) */
|
||||
|
||||
/* Definition of `FU_EXTERN'. */
|
||||
|
||||
#if !defined(FU_INLINE)
|
||||
# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
# define FU_INLINE inline
|
||||
# elif defined(__cplusplus)
|
||||
# define FU_INLINE inline
|
||||
# elif defined(__GNUC__)
|
||||
# define FU_INLINE __inline__
|
||||
# else
|
||||
# define FU_INLINE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Definition of the `FU_BOXABLE'. */
|
||||
|
||||
#if defined(__has_attribute) && __has_attribute(objc_boxable)
|
||||
# define FU_BOXABLE __attribute__((objc_boxable))
|
||||
#else
|
||||
# define FU_BOXABLE
|
||||
#endif
|
||||
|
||||
struct FUAuthPack {
|
||||
char *authData;
|
||||
int authDataSize;
|
||||
};
|
||||
|
||||
typedef struct FUAuthPack FUAuthPack;
|
||||
FU_EXTERN FUAuthPack FUAuthPackMake(char *authData, int authDataSize);
|
||||
|
||||
#pragma mark - FUPosition
|
||||
|
||||
struct FUPosition {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
typedef struct FU_BOXABLE FUPosition FUPosition;
|
||||
FU_EXTERN FUPosition FUPositionMake(float x, float y, float z);
|
||||
FU_EXTERN FUPosition FUPositionMakeWithX(FUPosition position, float x);
|
||||
FU_EXTERN FUPosition FUPositionMakeWithY(FUPosition position, float y);
|
||||
FU_EXTERN FUPosition FUPositionMakeWithZ(FUPosition position, float z);
|
||||
FU_EXTERN BOOL FUPositionIsEqual(FUPosition position1, FUPosition position2);
|
||||
|
||||
#pragma mark - FUColor
|
||||
|
||||
struct FUColor {
|
||||
double r;
|
||||
double g;
|
||||
double b;
|
||||
double a;
|
||||
};
|
||||
typedef struct FUColor FUColor;
|
||||
FU_EXTERN FUColor FUColorMake(double r, double g, double b, double a);
|
||||
FU_EXTERN FUColor FUColorMakeWithR(FUColor color, double r);
|
||||
FU_EXTERN FUColor FUColorMakeWithG(FUColor color, double g);
|
||||
FU_EXTERN FUColor FUColorMakeWithB(FUColor color, double b);
|
||||
FU_EXTERN FUColor FUColorMakeWithA(FUColor color, double a);
|
||||
FU_EXTERN FUColor FUColorMakeWithUIColor(UIColor *color);
|
||||
FU_EXTERN BOOL FUColorIsEqual(FUColor color1, FUColor color2);
|
||||
|
||||
#pragma mark - FURGBColor
|
||||
struct FURGBColor {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
};
|
||||
typedef struct FU_BOXABLE FURGBColor FURGBColor;
|
||||
FU_EXTERN FURGBColor FURGBColorMake(float r, float g, float b);
|
||||
FU_EXTERN FURGBColor FURGBColorMakeWithR(FURGBColor color, float r);
|
||||
FU_EXTERN FURGBColor FURGBColorMakeWithG(FURGBColor color, float g);
|
||||
FU_EXTERN FURGBColor FURGBColorMakeWithB(FURGBColor color, float b);
|
||||
FU_EXTERN FURGBColor FURGBColorMakeWithUIColor(UIColor *color);
|
||||
FU_EXTERN FURGBColor FURGBColorMakeWithNSData(NSData *data);
|
||||
FU_EXTERN BOOL FURGBColorIsEqual(FURGBColor color1, FURGBColor color2);
|
||||
|
||||
#pragma mark - FUBlendshape
|
||||
|
||||
struct FUBlendshape {
|
||||
float *expression;
|
||||
int expressionCount;
|
||||
};
|
||||
typedef struct FUBlendshape FUBlendshape;
|
||||
FU_EXTERN FUBlendshape FUBlendshapeMake(float *expression, int expressionCount);
|
||||
|
||||
#pragma mark - FUBlendshapeWeight
|
||||
|
||||
struct FUBlendshapeWeight {
|
||||
float *expressionWeight;
|
||||
int expressionCount;
|
||||
};
|
||||
typedef struct FUBlendshapeWeight FUBlendshapeWeight;
|
||||
FU_EXTERN FUBlendshapeWeight FUBlendshapeWeightMake(float *expressionWeight, int expressionCount);
|
||||
|
||||
struct FUShadowBias {
|
||||
float uniformBias;
|
||||
float normalBias;
|
||||
};
|
||||
typedef struct FUShadowBias FUShadowBias;
|
||||
FU_EXTERN FUShadowBias FUShadowBiasMake(float uniformBias, float normalBias);
|
||||
|
||||
struct FUGestureID {
|
||||
int left;
|
||||
int right;
|
||||
};
|
||||
typedef struct FUGestureID FUGestureID;
|
||||
|
||||
struct FUPixelBufferInfo {
|
||||
OSType format;
|
||||
CGSize size;
|
||||
|
||||
size_t stride0;
|
||||
size_t stride1;
|
||||
|
||||
size_t dataSize;
|
||||
};
|
||||
typedef struct FUPixelBufferInfo FUPixelBufferInfo;
|
||||
FU_EXTERN FUPixelBufferInfo FUPixelBufferInfoMake(CVPixelBufferRef pixelBuffer);
|
||||
|
||||
struct FULandMark {
|
||||
double *landMarks;
|
||||
int landMarksCount;
|
||||
};
|
||||
typedef struct FULandMark FULandMark;
|
||||
FU_EXTERN FULandMark FULandMarkMake(double *landMarks, int landMarksCount);
|
||||
|
||||
|
||||
#pragma mark - LABColor
|
||||
struct FULABColor {
|
||||
float l;
|
||||
float a;
|
||||
float b;
|
||||
};
|
||||
typedef struct FULABColor FULABColor;
|
||||
FU_EXTERN FULABColor FULABColorMake(float l, float a, float b);
|
||||
FU_EXTERN FULABColor FULABColorMakeWithL(FULABColor color, float l);
|
||||
FU_EXTERN FULABColor FULABColorMakeWithA(FULABColor color, float a);
|
||||
FU_EXTERN FULABColor FULABColorMakeWithB(FULABColor color, float b);
|
||||
FU_EXTERN BOOL FULABColorIsEqual(FULABColor color1, FULABColor color2);
|
||||
|
||||
extern FULABColor FULABColorInvalid;
|
||||
extern FURGBColor FURGBColorInvalid;
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// FUVideoComponentDefines.h
|
||||
// FUVideoComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/5/16.
|
||||
//
|
||||
|
||||
#ifndef FUVideoComponentDefines_h
|
||||
#define FUVideoComponentDefines_h
|
||||
|
||||
/// 弱引用对象
|
||||
#define FUWeakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
|
||||
|
||||
/// 强引用对象
|
||||
#define FUStrongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
|
||||
|
||||
/// 视频方向
|
||||
typedef NS_ENUM(NSInteger, FUVideoOrientation) {
|
||||
FUVideoOrientationPortrait = 0,
|
||||
FUVideoOrientationLandscapeRight,
|
||||
FUVideoOrientationUpsideDown,
|
||||
FUVideoOrientationLandscapeLeft
|
||||
};
|
||||
|
||||
#endif /* FUVideoComponentDefines_h */
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// FUVideoProcessor.h
|
||||
// FUVideoComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/5/27.
|
||||
//
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import "FUVideoSettings.h"
|
||||
#import "FUVideoReader.h"
|
||||
#import "FUVideoWriter.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUVideoProcessor : NSObject
|
||||
|
||||
/// 视频帧编码前处理,不设置则直接编码
|
||||
@property (nonatomic, copy) CVPixelBufferRef (^processingVideoBufferHandler)(CVPixelBufferRef videoPixelBuffer, CGFloat time);
|
||||
|
||||
/// 音频帧编码前处理,不设置则直接编码
|
||||
@property (nonatomic, copy) CMSampleBufferRef (^processingAudioBufferHandler)(CMSampleBufferRef audioSampleBuffer);
|
||||
|
||||
/// 处理流程完成
|
||||
@property (nonatomic, copy) void (^processingFinishedHandler)(void);
|
||||
|
||||
@property (nonatomic, strong, readonly) FUVideoReader *reader;
|
||||
|
||||
@property (nonatomic, strong, readonly) FUVideoWriter *writer;
|
||||
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
|
||||
- (instancetype)initWithReadingURL:(NSURL *)readingURL
|
||||
writingURL:(NSURL *)writingURL;
|
||||
|
||||
/// 初始化方法
|
||||
/// @param readingURL 解码视频URL
|
||||
/// @param readerSettings 解码设置,nil时使用默认设置
|
||||
/// @param writingURL 编码视频URL
|
||||
/// @param writerSettings 编码设置,nil时使用默认设置
|
||||
- (instancetype)initWithReadingURL:(NSURL *)readingURL
|
||||
readerSettings:(nullable FUVideoReaderSettings *)readerSettings
|
||||
writingURL:(NSURL *)writingURL
|
||||
writerSettings:(nullable FUVideoWriterSettings *)writerSettings;
|
||||
|
||||
- (void)startProcessing;
|
||||
|
||||
/// 内部会销毁解码器和编码器
|
||||
- (void)cancelProcessing;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// FUVideoReader.h
|
||||
// FUVideoComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/5/9.
|
||||
//
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
#import "FUVideoComponentDefines.h"
|
||||
#import "FUVideoSettings.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol FUVideoReaderDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
/// 视频帧输出,注意及时释放videoSampleBuffer
|
||||
- (void)videoReaderDidOutputVideoSampleBuffer:(CMSampleBufferRef)videoSampleBuffer;
|
||||
|
||||
/// 音频帧输出,注意及时释放audioSampleBuffer
|
||||
- (void)videoReaderDidOutputAudioSampleBuffer:(CMSampleBufferRef)audioSampleBuffer;
|
||||
|
||||
/// 视频解码完成
|
||||
- (void)videoReaderDidFinishVideoReading;
|
||||
|
||||
/// 音频解码完成
|
||||
- (void)videoReaderDidFinishAudioReading;
|
||||
|
||||
/// 解码完成
|
||||
- (void)videoReaderDidFinishReading;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUVideoReader : NSObject
|
||||
|
||||
/// 是否正在解码
|
||||
@property (nonatomic, assign, readonly) BOOL isReading;
|
||||
/// 视频尺寸
|
||||
@property (nonatomic, assign, readonly) CGSize videoSize;
|
||||
/// 视频方向
|
||||
@property (nonatomic, assign, readonly) FUVideoOrientation videoOrientation;
|
||||
/// 当前视频是否包含音频轨道
|
||||
@property (nonatomic, assign, readonly) BOOL containAudioTrack;
|
||||
/// 视频时长,单位秒
|
||||
@property (nonatomic, assign, readonly) CGFloat duration;
|
||||
|
||||
@property (nonatomic, weak) id<FUVideoReaderDelegate> delegate;
|
||||
|
||||
@property (nonatomic, strong) FUVideoReaderSettings *readerSettings;
|
||||
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithURL:(NSURL *)URL;
|
||||
|
||||
- (instancetype)initWithURL:(NSURL *)URL settings:(nullable FUVideoReaderSettings *)settings;
|
||||
|
||||
- (instancetype)initWithAsset:(AVAsset *)asset;
|
||||
|
||||
- (instancetype)initWithAsset:(AVAsset *)asset settings:(nullable FUVideoReaderSettings *)settings;
|
||||
|
||||
/// 开始解码
|
||||
/// @note 内部自动解码为异步
|
||||
- (void)start;
|
||||
|
||||
/// 停止解码
|
||||
- (void)stop;
|
||||
|
||||
- (BOOL)readNextVideoBuffer;
|
||||
|
||||
- (BOOL)readNextAudioBuffer;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// FUVideoSettings.h
|
||||
// FUVideoComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/5/27.
|
||||
//
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import "FUVideoComponentDefines.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUVideoReaderSettings : NSObject
|
||||
|
||||
/// 是否自动解码,默认为NO
|
||||
/// @note 如果为NO,可以调用FUVideoReader实例的readNextVideoBuffer和readNextAudioBuffer方法逐帧读取
|
||||
@property (nonatomic, assign) BOOL readingAutomatically;
|
||||
|
||||
/// 是否需要音频轨道,默认为YES
|
||||
@property (nonatomic, assign) BOOL needsAudioTrack;
|
||||
|
||||
/// 以视频真实码率或者以默认速度解码,默认为YES(视频真实码率)
|
||||
@property (nonatomic, assign) BOOL readAtVideoRate;
|
||||
|
||||
/// 是否需要循环解码,默认为NO
|
||||
@property (nonatomic, assign) BOOL needsRepeat;
|
||||
|
||||
/// 视频解码格式,默认为kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
|
||||
@property (nonatomic) OSType videoOutputFormat;
|
||||
|
||||
/// 音频解码格式,默认为kAudioFormatLinearPCM (最高保真度)
|
||||
@property (nonatomic) AudioFormatID audioOutputFormat;
|
||||
|
||||
/// 恢复默认设置
|
||||
- (void)resetToDefault;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUVideoWriterSettings : NSObject
|
||||
|
||||
/// 是否需要音频轨道,默认为YES
|
||||
@property (nonatomic, assign) BOOL needsAudioTrack;
|
||||
|
||||
/// 文件格式,默认为AVFileTypeQuickTimeMovie
|
||||
@property (nonatomic, copy) AVFileType fileType;
|
||||
|
||||
/// 是否实时数据源,默认为NO
|
||||
@property (nonatomic, assign) BOOL isRealTimeData;
|
||||
|
||||
/// 视频方向,默认为FUVideoOrientationPortrait
|
||||
@property (nonatomic, assign) FUVideoOrientation videoOrientation;
|
||||
|
||||
/// 视频编码格式,默认为AVVideoCodecH264
|
||||
@property (nonatomic, copy) AVVideoCodecType videoInputFormat;
|
||||
|
||||
/// 音频编码格式,默认为kAudioFormatMPEG4AAC
|
||||
@property (nonatomic) AudioFormatID audioInputFormat;
|
||||
|
||||
/// 音频声道数量,默认为2
|
||||
@property (nonatomic, assign) NSInteger audioChannels;
|
||||
|
||||
/// 音频码率,默认为当前硬件码率
|
||||
@property (nonatomic) double audioRate;
|
||||
|
||||
/// 恢复默认设置
|
||||
- (void)resetToDefault;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// FUVideoWriter.h
|
||||
// FUVideoComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/5/9.
|
||||
//
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
#import "FUVideoComponentDefines.h"
|
||||
#import "FUVideoSettings.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUVideoWriter : NSObject
|
||||
|
||||
@property (nonatomic, assign, readonly) BOOL isWriting;
|
||||
@property (nonatomic, strong, readonly) NSURL *videoURL;
|
||||
@property (nonatomic, strong, readonly) AVAssetWriterInput *videoInput;
|
||||
@property (nonatomic, strong, readonly) AVAssetWriterInput *audioInput;
|
||||
/// 视频数据允许写入回调,star()方法调用前赋值
|
||||
@property (nonatomic, copy) BOOL (^videoInputReadyHandler)(void);
|
||||
/// 音频数据允许写入回调,start()方法调用前赋值
|
||||
@property (nonatomic, copy) BOOL (^audioInputReadyHandler)(void);
|
||||
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithVideoURL:(NSURL *)URL
|
||||
videoSize:(CGSize)size;
|
||||
|
||||
/// 初始化方法
|
||||
/// @param URL 文件保存路径(如果已经存在文件,会先删除原文件)
|
||||
/// @param size 视频尺寸
|
||||
/// @param settings 编码设置,nil时会使用默认设置
|
||||
- (instancetype)initWithVideoURL:(NSURL *)URL
|
||||
videoSize:(CGSize)size
|
||||
setting:(nullable FUVideoWriterSettings *)settings;
|
||||
|
||||
- (void)start;
|
||||
|
||||
- (void)stop;
|
||||
|
||||
/// 写入完成后必须调用该方法
|
||||
- (void)finishWritingWithCompletion:(nullable void (^)(void))completion;
|
||||
|
||||
- (void)appendVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer;
|
||||
|
||||
- (void)appendPixelBuffer:(CVPixelBufferRef)pixelBuffer time:(CMTime)timeStamp;
|
||||
|
||||
- (void)appendAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user