c的注意事项

注意事项

oc 调用 c c++ 需要注意的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef LearnC_h
#define LearnC_h
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
void learnCplus(int a, int b);
#ifdef __cplusplus
}
#endif
#endif /* LearnC_h */

hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef LearnC___hpp
#define LearnC___hpp
#include <string>
#include <stdio.h>
void learnCplusplus(int a, int b);
class cppObject
{
public:
void exampleMethod(const std::string& str);
};
#endif /* LearnC___hpp */

cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//
// LearnC++.cpp
// LearnOCandCandC++
//
// Created by 林伟池 on 16/2/23.
// Copyright © 2016年 林伟池. All rights reserved.
//
#include "LearnC++.hpp"
#include <iostream>
void learnCplusplus(int a, int b) {
printf("cplusplus%d\n", a + b);
}
void cppObject::exampleMethod(const std::string &str)
{
std::cout << str;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#import "LearnC.h"
#import "LearnC++.hpp"
#import "LearnOCinCPP.h"
@interface ViewController ()
@end
@implementation ViewController
{
cppObject* object;
}
- (void)viewDidLoad {
[super viewDidLoad];
learnCplus(1, 2); //在OC中使用c
learnCplusplus(1, 2); //在OC中用C++编译的C
//在OC中使用C++的类
object = new cppObject();
NSString* str = @"GAO高级\n";
std::string cpp_str([str UTF8String], [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
object->exampleMethod(cpp_str);
delete object;
object = NULL; //记得删除
//在OC使用的C++类中 使用OC
LY::OCinCPP* cpp = new LY::OCinCPP();
cpp->lyRun();
}

参考

Lede运行v2ray

LEDE 运行v2ray不完美的解决办法

从官网下载v2ray的运行文件放在/usr/bin/v2ray 目录下
v2ray release 下载

将config.json(或者你直接改名为v2ray.json)文件放在/etc/v2ray.json
将 /usr/bin/v2ray 和 /etc/v2ray.json 文件赋予权限 直接猛点的权限赋值方法 chomd 777 path

1
/usr/bin/v2ray --config /etc/v2ray.json

对应修改config.json文件后传到自己的lede的对应的目录中去
然后在网络设置中–代理—网页代理,安全网络代理中添加 你的路由器ip e.g. 192.168.1.111 加上对应的端口 1080;socks的代理配置同理

如果inbound 中的protocol: socks,需要在settings中增加 “auth”: “noauth”

1
2
3
4
5
6
"inbound": {
"port": 1080,
"protocol": "socks",
"settings": {
"auth": "noauth"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
{
"log": {
"error": "/var/log/v2ray/error.log",
"loglevel": "warning"
},
"inbound": {
"port": 1080,
"protocol": "http",
"settings": {}
},
"outbound": {
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "v2ray.cool",
"port": 10086,
"users": [
{
"id": "a3482e88-686a-4a58-8126-99c9df64b7bf",
"alterId": 64,
"security": "auto"
}
]
}
]
},
"mux": {
"enabled": true
}
},
"outboundDetour": [
{
"protocol": "freedom",
"settings": {},
"tag": "direct"
}
],
"dns": {
"servers": [
"8.8.8.8",
"8.8.4.4",
"localhost"
]
},
"routing": {
"strategy": "rules",
"settings": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"port": "1-52",
"outboundTag": "direct"
},
{
"type": "field",
"port": "54-79",
"outboundTag": "direct"
},
{
"type": "field",
"port": "81-442",
"outboundTag": "direct"
},
{
"type": "field",
"port": "444-65535",
"outboundTag": "direct"
},
{
"type": "chinasites",
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"0.0.0.0/8",
"10.0.0.0/8",
"100.64.0.0/10",
"127.0.0.0/8",
"169.254.0.0/16",
"172.16.0.0/12",
"192.0.0.0/24",
"192.0.2.0/24",
"192.168.0.0/16",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"::1/128",
"fc00::/7",
"fe80::/10"
],
"outboundTag": "direct"
},
{
"type": "chinaip",
"outboundTag": "direct"
}
]
}
}
}

最新更新2017 8.16

https://github.com/v2ray/v2ray-core/issues/483
用otaku的一段代码实现了v2ray的进程守护

还是放在 /etc/init.d/v2ray

1
2
3
4
5
6
7
8
9
10
11
12
13
14
START=90
USE_PROCD=1
start_service() {
mkdir /var/log/v2ray > /dev/null 2>&1
procd_open_instance
procd_set_param respawn
procd_set_param command /usr/bin/v2ray -config /etc/v2ray/config.json
procd_set_param file /etc/v2ray/config.json
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param pidfile /var/run/v2ray.pid
procd_close_instance
}

V2Ray 配置ss & vmess

V2Ray 配置文件设置

满足VMESS & SS协议

安装步骤

1 (以搬瓦工的Center OS 7 bbr)先用ssh登录

1
ssh root@162.219.121.23x -p 27530

2 Bash命令安装

1
bash <(curl -L -s https://install.direct/go.sh)

3 编辑服务端配置文件满足VMESS & SS协议

1
vi /etc/v2ray/config.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
{
"log" : {
"access": "/var/log/v2ray/access.log",
"error": "/var/log/v2ray/error.log",
"loglevel": "warning"
},
"inbound": {
"port": 21059,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "7ce007bc-47ea-45c1-9294-e37168186c4e",
"level": 1,
"alterId": 64
}
]
}
},
"outbound": {
"protocol": "freedom",
"settings": {}
},
"inboundDetour": [
{
"protocol": "shadowsocks",
"port": 21058,
"settings": {
"method": "aes-256-cfb",
"password": "v2ray",
"udp": false
}
}
],
"outboundDetour": [
{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}
],
"routing": {
"strategy": "rules",
"settings": {
"rules": [
{
"type": "field",
"ip": [
"0.0.0.0/8",
"10.0.0.0/8",
"100.64.0.0/10",
"127.0.0.0/8",
"169.254.0.0/16",
"172.16.0.0/12",
"192.0.0.0/24",
"192.0.2.0/24",
"192.168.0.0/16",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"::1/128",
"fc00::/7",
"fe80::/10"
],
"outboundTag": "blocked"
}
]
}
}
}

配置文件设置好后,可以用命令测试

1
./v2ray --test --config v2ray-client.json

启动相关命令

  1. 编辑 /etc/v2ray/config.json 文件来配置你需要的代理方式;

  2. 运行 service v2ray start 来启动 V2Ray 进程;

  3. 之后可以使用 service v2ray start|stop|status|reload|restart|force-reload 控制 V2Ray 的运行

1
service v2ray status | start ...

注意事项:

以上配置适用于root权限下操作,若由于权限不足请自行搜索解决

如果遇到ssh无法登录的情况,可以先rm ~/.ssh/xxx 对应的文件然后再重新连接

uuid生成网站

路由追踪

配置生成器

这个配置生成只有一种协议,如果要支持多种协议,请参考上面贴出的code,分别为 inbound inboundDetour

在 iOS8以上工程创建通用的framework

在 iOS8以上工程创建通用的framework 以及如何适配 swift module

参考链接

改良链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/bin/sh
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}/iOS"
# Step 1. Build Device and Simulator versions on iOS
xcodebuild -workspace "${PROJECT_NAME}.xcworkspace" -scheme "${PROJECT_NAME}" -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6' clean build
xcodebuild -workspace "${PROJECT_NAME}.xcworkspace" -scheme "${PROJECT_NAME}" -sdk iphoneos clean build
# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/iOS"
# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/iOS/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 4. Convenience step to copy the framework to the project's directory
mkdir -p "${TMPDIR}/${PROJECT_NAME}/Frameworks/iOS"
cp -R "${UNIVERSAL_OUTPUTFOLDER}/iOS/${PROJECT_NAME}.framework" "${TMPDIR}/${PROJECT_NAME}/Frameworks/iOS"
# Step 6. Create .tar.gz file for posting on the binary repository
cd "${TMPDIR}"
# We nest the framework inside a Frameworks folder so that it unarchives correctly
tar -zcf "${PROJECT_NAME}.framework.tar.gz" "${PROJECT_NAME}/Frameworks/"
mv "${PROJECT_NAME}.framework.tar.gz" "${PROJECT_DIR}/"
# Step 7. Convenience step to open the project's directory in Finder
#open "${PROJECT_DIR}"

BS fastlane的简单配置

简要记录如何通过 fastlane 和 jenkins实现自动打包上传蒲公英

环境: 1.Xcode 8.3.x 2.Jenkins 3.Fastlane

初次使用使用

1
fastlane init

输入对应的 apple id 账号和密码

下面我将粘贴 fastlane 目录结构的对应文件的内容

1
2
3
4
5
Fastlane
--- Appfile
--- Fastfile
--- Pluginfile //新版本中貌似不这样使用了

Appfile

1
2
3
4
5
6
7
app_identifier "com.XXX.app.suza.beta" # The bundle identifier of your app
apple_id "hai.duan@XXX.com.cn" # Your Apple email address
team_id "XXX" # Developer Portal Team ID
# you can even provide different app identifiers, Apple IDs and team names per lane:
# More information: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Appfile.md

Fastfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# update_fastlane
# Update this, if you use features of a newer version
fastlane_version "2.23.0"
default_platform :ios
platform :ios do
before_all do
cocoapods
end
desc "Runs all the tests"
lane :test do
scan
end
desc "Submit a new Beta Build to Apple TestFlight"
desc "This will also make sure the profile is up to date"
lane :beta do
# match(type: "appstore") # more information: https://codesigning.guide
gym(scheme: "BeSquare Beta",export_method: "ad-hoc") # Build your app - more options available
#pilot
# sh "your_script.sh"
# You can also use other beta testing services here (run `fastlane actions`)
end
desc "Deploy a new version to the App Store"
lane :release do
# match(type: "appstore")
# snapshot
gym(scheme: "BeSquare Beta",export_method: "appstore") # Build your app - more options available
deliver(force: true)
# frameit
end
# You can define as many lanes as you want
after_all do |lane|
# This block is called, only if the executed lane was successful
# slack(
# message: "Successfully deployed new App Update."
# )
end
error do |lane, exception|
# slack(
# message: exception.message,
# success: false
# )
end
end

Jenkins
—- Execute shell

1
2
3
4
5
6
pwd
cd SUZA
fastlane beta
GIT_COMMIT_MSG=`git log -1 --pretty=%h:%an:%B`
curl -F "updateDescription=${GIT_COMMIT_MSG}" -F "file=@/Users/duanhai/.jenkins/workspace/XXX/XX22DD/XXX Beta.ipa" -F "uKey=27ee4291086a9ba71c2f890e3d0bdc20" -F "_api_key=729c278fe701cc64bcf9eb14d83fd2fa" https://qiniu-storage.pgyer.com/apiv1/app/upload

kiwiDoc

Kiwi人脸跟踪SDK快速集成指南(iOS)

kiwi人脸跟踪SDK,主要功能包括:

  • 静态图片的人脸以及关键点位置检测
  • 68个人脸关键点的实时检测与跟踪(单人脸/多人脸)
  • 美颜、哈哈镜等实时滤镜功能
  • 人脸Pose参数估计
  • 趣味2D贴纸

我们的SDK针对移动端,在算法效率、硬件占用、性能精度等方面进行了相关优化,使其适用于移动端直播,美颜相机,滤镜相机,趣味贴纸,虚拟美妆等应用场景。

流程图

这个文档将演示如何利用我们的demo快速入门,并详细描述具体集成步骤。

Demo快速入门

该demo基于七牛的直播SDK,实现了在直播的场景下实现人脸跟踪以及趣味贴纸。

准备环境

开发环境要求

软件

* XCode 6.0 或以上版本
* iOS 7.0 或以上版本

硬件

* 支持语音/视频的真机设备

编译代码示例

  1. 用XCode打开demo工程文件(PLMediaStreamingKitDemo)。代码包含以下目录结构

  2. 选中项目,如下图所示,点击 “Build and Run” 按钮进行编译

    示例截图

| |

p.s. 该示例只支持在真机上实现功能,不支持模拟器。编译完成后,即可运行。

具体集成步骤

第一步:准备环境

软件

  • XCode 6.0 或以上版本
  • iOS 7.0 或以上版本

硬件

  • 支持语音/视频的真机设备

第二步:项目所需库

  • kiwi提供(请从sdk文件夹中获取)
    • libfaceTrackerSDK.a(人脸捕捉SDK)
    • libKiwiFaceSDK.a(UI+视频帧渲染SDK)
  • 系统库 (xcode自带)
    • UIKit.framework
    • Foundation.framework

第三步:部署工程

1. 导入 libKiwiFaceSDK.a 文件和所有包含的头文件、实现文件、资源文件。(我们提供了两种libKiwiFaceSDK.a文件。libKiwiFaceSDK.a同时支持模拟器与真机,供开发调试使用。libKiwiFaceSDK_release.a仅支持真机,供发布使用。)

  ![](images/KiwiFaceSDK.jpg)

2. 导入Tracker 人脸捕捉的SDK包和StickerManager。(我们提供了两种libfaceTrackerSDK.a文件。libfaceTrackerSDK_lic.a同时支持模拟器与真机,供开发调试使用。libfaceTrackerSDK_release.a仅支持真机,供发布使用。)

  ![](images/Tracker.jpg)

  ![](images/StickerManager.jpg)

  这里注意tracker包的models文件夹和StickerManager文件夹下的stickers贴纸文件夹,必须只是导入引用,不要包含到项目工程里面来(文件夹图标为蓝色)。如下图设置:

  ![](images/target-settings.png)

3. 导入GPUImage,用于视频渲染(我们提供了两种libGPUImage.a文件。libGPUImage.a同时支持模拟器与真机,供开发调试使用。libGPUImage_release.a仅支持真机,供发布使用。)

4. 如有需要,导入libyuv

  sdk视频帧的渲染暂时只支持NV21格式的传入 如果应用视频帧是YUV或者其他视频流类型 需要导入视频流格式的转换类。

5. 导入
opencv3.framework

  注意,从官网下载的包有可能被错误的命名为opencv2.framework。

第四步:贴纸配置

如果有需要,请配置贴纸。贴纸相关文件存放在stickers目录下,一套贴纸对应一个目录,每套贴纸包含一个config.json文件,其中配置了音效文件名及每个item参数等信息。其结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|--[sticker_1] (贴纸1)
| |--config.json (贴纸配置文件)
| |--[audio](音频文件)
| |--[preview](贴纸预览图)
| |--[item_1](贴纸序列图文件夹1)
| | |--[frame_1](贴纸序列图1)
| | |--[frame_2](贴纸序列图2)
| | |--...
| | |--[frame_n](贴纸序列图n)
| |--[item_2](贴纸序列图文件夹2)
| |--...
| |--[item_n](贴纸序列图文件夹n)
|--[sticker_2](贴纸2)
|--...
|--[sticker_n](贴纸n)
|—StickerConfig.json(总配置文件)

程序靠读取在stickers文件夹下的StickerConfig.json显示相应的贴纸和图标。

注意,使用贴纸云,需要在Info.plist中加入App Transport Security Settings字段,并将Allow Arbitrary Loads设置为YES。
具体的json文件格式如下:

StickerConfig.json

参数名称 意义
name 贴纸的名称(UI显示和贴纸的识别)
dir 贴纸存放路径文件夹名称
category 类别(贴纸类型的区分或分组)
thumb 贴纸图标的文件名(与声音在同一文件夹下)
voiced true(有声音)false(没有声音播放)
downloaded 是否已经下载。如果没有下载,程序则可以去下载到指定目录后更改该状态

config.json

参数名称 意义
type 贴纸显示的位置类型(脸部、全屏)
facePos 贴纸在脸部的位置
scaleWidthOffset 贴纸宽度缩放系数
scaleHeightOffset 贴纸高度缩放系数
scaleXOffset 贴纸在脸部水平方向偏移系数
scaleYOffset 贴纸在脸部垂直方向偏移系数
alignPos 边缘item参数
alignX 边缘水平方向偏移系数
alignY 边缘垂直方向系数
frameFolder 贴纸资源目录(包括一组图片序列帧)
frameNum 帧数(一组序列帧组成一个动画效果)
frameDuration 每帧的间隔(秒)
frameWidth 图片的宽
frameHeight 图片的高
trigerType 触发条件,默认0,始终显示

编写config.json文件可使用我司提供的工具 https://apps.kiwiapp.mobi/sticker.html 进行调试生成。

第五步:调用API

使用SDK内置UI

如果直接使用我们SDK内置的UI, 可以在页面的viewDidload里面初始化SDK。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 获得SDK操作类的实例对象 */
self.kwSdkUI = [KiwiFaceSDK_UI shareManagerUI];
/* 设置SDK内置UI的 ViewController 如果不用内置UI 不用设置 */
[self.kwSdkUI setViewDelegate:self];
/* 初始化SDK 一些渲染对象以及初始参数 */
[self.kwSdkUI.kwSdk initSdk];
/* 如果使用内置UI 该属性是判断是否清除原有项目的页面UI 如果原有UI功能少 可以用内置UI 替代 一般来说用不到 */
self.kwSdkUI.isClearOldUI = NO;
/* 初始化内置UI */
[self.kwSdkUI initSDKUI];
/* 渲染视频帧,在每一帧视频代理函数中调用 */
self.kwSdkUI.kwSdk = [KiwiFaceSDK sharedManager];
/*
对每一帧的视频图像进行人脸捕捉 并对当前选择的滤镜进行视频帧渲染
pixelBuffer:每一帧的像素流
cvMobileRotate :屏幕方向(横竖屏)
mirrored: 是否是镜像
*/
[kwSdk.renderer processPixelBuffer:pixelBuffer withRotation:cvMobileRotate mirrored:mirrored];
使用sdk自带功能
  • 初始化具体功能:

    • 初始化普通滤镜或贴纸集合

      1
      2
      3
      4
      5
      6
      self.filters = @[
      //描点
      [FTPointsRenderer new],
      //贴纸
      [FTStickerRenderer new]
      ];
    • 初始化哈哈镜滤镜集合

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      self.distortionFilters = @[
      //方脸
      [GPUImageSquareFaceFilter new],
      //ET脸
      [ETnewFilter new],
      //胖脸
      [FatFaceFilter new],
      //蛇精脸
      [SlimFaceFilter new],
      //梨脸
      [PearFaceDistortionFilter new]
      ];
    • 初始化美颜滤镜集合

      1
      2
      3
      4
      5
      6
      7
      8
      9
      self.beautifyFilters = @[
      //大眼
      [SmallFaceBigEyeFilter new]
      ];
      self.beautifyNewFilters = @[
      //美颜
      [GPUImageBeautifyFilter new]
      ];
    • 初始化全局滤镜集合

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      self.lookupFilters = @[
      //Nature
      [[FTLookupFilter alloc] initWithType:FTLookupTypeNature],
      //Sweety
      [[FTLookupFilter alloc] initWithType:FTLookupTypeSweety],
      //Clean
      [[FTLookupFilter alloc] initWithType:FTLookupTypeClean],
      //Peach
      [[FTLookupFilter alloc] initWithType:FTLookupTypePeach],
      //Rosy
      [[FTLookupFilter alloc] initWithType:FTLookupTypeRosy],
      //Urban
      [[FTLookupFilter alloc] initWithType:FTLookupTypeUrban]
      ];
  • 调用具体功能:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //调用美颜
    [self.renderer addFilter:self.beautifyNewFilters[0]];
    //调用描点
    [self.renderer addFilter:self.filters[0]];
    //调用哈哈镜
    [self.renderer addFilter:self.currentDistortionFilter];
    //调用滤镜
    [self.renderer addFilter:self.currentLookupFilter];
    //调用贴纸
    [self.renderer addFilter:self.filters[1]];
  • 去除具体功能:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //去除美颜
    [self.renderer removeFilter:self.beautifyNewFilters[0]];
    //去除描点
    [self.renderer removeFilter:self.filters[0]];
    //去除哈哈镜
    [self.renderer removeFilter:self.currentDistortionFilter];
    //去除滤镜
    [self.renderer removeFilter:self.currentLookupFilter];
    //去除贴纸
    [(FTStickerRenderer *)self.filters[1] setSticker:nil];
自定义功能扩展
  • 增加特定滤镜,进行渲染:

    在 sdk入口类中,有一个类型为KWRenderer的渲染类,由他来控制滤镜的增加。

    1
    [KiwiFaceSDK.KWRenderer addFilter: GPUImageOutput<GPUImageInput, KWRenderProtocol> *];

    滤镜对象必须遵守GPUImageInput和KWRenderProtocol两个协议才能正常被人脸捕捉和渲染。

  • 删除特定滤镜,停止渲染:

    1
    [KiwiFaceSDK.KWRenderer removeFilter: GPUImageOutput<GPUImageInput, KWRenderProtocol> *];
  • 人脸捕捉之后,在渲染视频帧之前可以对每一帧图像做自定义处理的回调block:

    1
    2
    3
    typedef void (^RenderAndGetFacePointsBlock)(unsigned char *pixels, int format, int width, int height,result_68_t *p_result, int rstNum, int orientation,int faceNum);
    //block属性
    @property (nonatomic, copy)RenderAndGetFacePointsBlock kwRenderBlock;

    block 回调用于在人脸捕捉之后,渲染之前,可以对视频帧进行自定已处理的接口。Block的3个参数可供处理和使用:

    • result :人脸坐标集合 (可能是多张人脸 是二维数组)
    • faceNum :捕捉到的人脸数量
    • pixelBuffer:单帧的像素流
释放内存

我们建议在离开页面的时候释放内存

1
[KiwiFaceSDK releaseManager];

Dispatch Semaphore & NSCondition

dispatch_semaphore 使用 http://www.cnblogs.com/snailHL/p/3906112.html

两个作用

加锁/数据同步

dispatch_semaphore_create

dispatch_semaphore_signal

dispatch_semaphore_wait

1
2
3
- (void)methodWithABlock:(DHBLK)blk{
blk(@"hahaha");
}

测试代码1 单个block

1
2
3
4
5
6
7
8
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[self methodWithABlock:^(id result){
//写block中做的事情
//结束等待
dispatch_semaphore_signal(sem);
}];
//等待信号
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);

测试代码2 多个 blcok

xxx.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[self methodWithABlock:^(id result){
//写block中做的事情
dispatch_semaphore_signal(sem);
[self methodWithABlock:^(id result){
//写block中做的事情
dispatch_semaphore_signal(sem);
}];
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);

测试代码3

1
2
3
4
5
6
7
8
9
10
11
12
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block int j = 0;
dispatch_async(queue, ^{
j = 100;
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"%d",j);
// j = 100

测试代码 4 加锁测试 ,反注释掉//

1
2
3
4
5
6
7
8
for (int i = 0; i < 100; i++) {
dispatch_async(queue, ^{
// 相当于加锁
// dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"i = %zd semaphore = %@", i, semaphore);
// 相当于解锁
// dispatch_semaphore_signal(semaphore);
});

NSCondition 的使用

NSCondition 的对象实际上作为一个锁和一个线程检查器:锁主要为了当检测条件时保护数据源,执行条件引发的任务;线程检查器主要是根据条件决定是否继续运行线程,即线程是否被阻塞。
http://www.jianshu.com/p/5d20c15ae690

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
NSCondition *condition = [[NSCondition alloc] init];
__block NSMutableArray *products = [[NSMutableArray alloc] initWithCapacity:10];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[condition lock];
while ([products count] == 0) {
NSLog(@"wait for products ");
[condition wait];
}
[products removeObjectAtIndex:0];
NSLog(@"custome a product");
[condition unlock];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[condition lock];
products = [NSMutableArray array];
[products addObject:@"oo"];
NSLog(@"produce a obj");
[condition signal];
[condition unlock];
});

异步下载图片完成后同步完成数据库再通知UI刷新的机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
- (void)receiveMessage:(MessageEntity *)message
{
NSCondition *condition = [[NSCondition alloc]init];
[condition lock];
NSInteger imageCount ;
void(^unlock)=^(){
while(!imageCount)
[condition signal];
}
imageCount++;
dowanloadImageFinished:^(UIImage *image){ //异步下载图片,下载完成的回调中
imageCount--;
unlock();
}
while(imageCount){
[condition wait];
}
[condition unLock];
}

以GPUImage 实现的延时摄影

用 semaphore 来筛选(关断)出时间间隔的图像 buffter.筛选出来的buffer 再筛入 WriterInputPixelBufferAdaptor.

https://github.com/yangfangxue/GPUImageRecord.git

1.dispatch timer 的用法

1
2
3
4
5
6
7
8
9
10
__weak typeof(self) ws =self;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), 0.5 * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(_timer, ^{
[ws defaultTimerHandel];
});
_seam = dispatch_semaphore_create(0);

//使用 timer 和销毁

1
2
3
dispatch_resume(_timer);
dispatch_cancel(_timer);

GPUImageVideoCamera 中回调方法CMSampleBufferRef的 lock

1
2
3
4
5
6
7
[_camera addTarget:self.preview];
//获取buffer
CVPixelBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CVPixelBufferLockBaseAddress(imageBuffer, 0);
_imageBuffer = CVPixelBufferRetain(imageBuffer);
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);

录制配置路径的时候需要检测是否存在,清除历史文件

完成录制时候加入condition 保护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[writerInput markAsFinished];
if(videoWriter.status == AVAssetWriterStatusWriting){
NSCondition *cond = [[NSCondition alloc] init];
[cond lock];
[videoWriter finishWritingWithCompletionHandler:^{
[cond lock];
[cond signal];
[cond unlock];
}];
[cond wait];
[cond unlock];
[self savePhotoCmare:self.url];
}