> ## Documentation Index
> Fetch the complete documentation index at: https://docs.facebetter.net/llms.txt
> Use this file to discover all available pages before exploring further.

# ベストプラクティス

> iOS Facebetter SDK 2.0 のパフォーマンスとアーキテクチャ

<Note>
  このページは SDK **2.0.0** に対応します。メイク / リシェイプ列挙: [パラメータ列挙](/ja/intro/makeup)。
</Note>

## 正しいフレームタイプを選ぶ

`processImage:` の**前**に `FBImageFrame.type` を設定します。エンジンメソッドに独立した処理モード引数はありません。

* **`FBFrameTypeVideo`（`1`）**: カメラプレビュー、ライブ配信、通話。遅延が低い。
* **`FBFrameTypeImage`（`0`）**: 静止画。効果が高い。

```objc theme={null}
input.type = FBFrameTypeVideo;
FBImageFrame *output = [engine processImage:input];
```

<h2 id="large-stills">
  大きな静止画（プレビューと書き出し）
</h2>

高解像度の静止画では、スライダーのたびに原寸を `processImage:` に渡さないでください。縮小したあとに原画を捨てないでください。

写真を開いたら完全な `UIImage` を残し、プレビュー用フレームを **1 枚**作ります（長辺は約 1280–1440、`createWithUIImage:`）。パラメータ調整はプレビュー（`FBFrameTypeImage`）、書き出しは同じ setter で全サイズをもう一度処理します。出力サイズは入力と同じです。カメラプレビューはキャプチャ解像度 + `FBFrameTypeVideo` のままです。

```objc theme={null}
preview.type = FBFrameTypeImage;
FBImageFrame *previewOut = [engine processImage:preview];

full.type = FBFrameTypeImage;
FBImageFrame *exportOut = [engine processImage:full];
```

## パラメータ範囲

* 美肌 / メイク / フィルター強度: `[0.0, 1.0]`。`0` はその項目をオフにします。
* リシェイプ（`setReshape:intensity:`）: **`[-1.0, 1.0]`**。`0` はオフ。正負は逆方向です。

ライブプレビューは小さめの値から始めてください。列挙の意味は [パラメータ列挙](/ja/intro/makeup) を参照してください。

```objc theme={null}
[engine setSmoothing:0.25f];
[engine setSmoothingStyle:FBSmoothingStyle_Natural];
[engine setWhitening:0.15f];
[engine setReshape:FBReshape_FaceThin intensity:0.12f];
[engine setBeautySkinOnly:YES];
```

## 1 つのエンジン、1 つのシリアルキュー

`createEngineWithConfig:` が返すのは**インスタンス**であり、プロセス単位のシングルトンではありません。セッションごとにエンジンを 1 つ保持し、**シリアルキュー**上で呼び出します（`externalContext = YES` の場合は GL スレッド）。

```objc theme={null}
@interface BeautyEngineManager : NSObject
@property (nonatomic, strong, readonly) FBBeautyEffectEngine *engine;
@property (nonatomic, strong, readonly) dispatch_queue_t queue;
+ (instancetype)sharedManager;
@end

@implementation BeautyEngineManager

+ (instancetype)sharedManager {
  static BeautyEngineManager *instance;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    instance = [[BeautyEngineManager alloc] init];
  });
  return instance;
}

- (instancetype)init {
  self = [super init];
  if (self) {
    _queue = dispatch_queue_create("com.facebetter.process", DISPATCH_QUEUE_SERIAL);
    FBEngineConfig *config = [[FBEngineConfig alloc] init];
    config.appId = @"your_app_id";
    config.appKey = @"your_app_key";
    _engine = [FBBeautyEffectEngine createEngineWithConfig:config];
  }
  return self;
}

- (void)process:(FBImageFrame *)input completion:(void (^)(FBImageFrame * _Nullable))completion {
  dispatch_async(self.queue, ^{
    input.type = FBFrameTypeVideo;
    FBImageFrame *output = [self.engine processImage:input];
    dispatch_async(dispatch_get_main_queue(), ^{
      completion(output);
    });
  });
}

@end
```

ごく小さい静止画以外は、メインスレッドで処理しないでください。複数の並行キューから同じエンジンに同時アクセスしないでください。

## メモリ

* ARC を使い、使い終わった `FBImageFrame` は `nil` にします。
* カメラがすでに NV12 / BGRA の場合、毎フレーム RGBA へ変換しないでください。
* フィルターとステッカーのテクスチャは、次の `processImage:`（GL スレッド）で作成されます。毎フレーム `setFilter:` / `setSticker:` せず、強度は `setFilterIntensity:` で変えます。
* `clearFilter`、`clearSticker`、`clearVirtualBackground`、`clearChromaKey` を使い、別エンジンを作らないでください。

## 外部 OpenGL ES

アプリがすでに GL コンテキストを持っている場合:

1. `config.externalContext = YES` を設定します。
2. **その GL スレッド**でエンジンを作成します。
3. `createWithTexture:width:height:stride:` でテクスチャをラップします。
4. 出力は `[output texture]` を使います。

入力テクスチャ、エンジン、出力テクスチャは同じコンテキスト上である必要があります。

## `getStats` で監視

独自タイマーより `FBEngineStats` を優先してください。

```objc theme={null}
FBEngineStats *stats = [engine getStats];
NSLog(@"fps=%.1f avg=%.2fms session=%.1fs",
      stats.fps, stats.avgProcessTimeMs, stats.sessionTimeS);
```

30 fps では `avgProcessTimeMs` は約 33 ms 未満が望ましいです。高い場合は解像度を下げ、`FBFrameTypeVideo` を使うか、不要なメイク / ステッカーをオフにします。

## ライフサイクル

エンジンは ViewController（またはセッションオブジェクト）の strong プロパティで保持します。セッション終了時は `dealloc` で `nil` にします。`viewWillDisappear` / `applicationDidEnterBackground` でキャプチャを止め、`processImage:` の呼び出しを止めます。専用の pause API はありません。

```objc theme={null}
- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];
  [self.captureSession stopRunning];
}

- (void)dealloc {
  self.beautyEffectEngine = nil;
}
```

`FBEngineCallbacks` の block では `__weak` を使い、循環参照を避けます。

## iOS キャプチャ

* プレビューは多くが NV12 または BGRA です。`createWithNV12:...` / `createWithBGRA:...` を使います。
* フロントカメラ: フレームに `setMirror:@"horizontal"`（ピクセルを先に反転する必要がある場合は `mirror:`）。
* カメラ権限: `Info.plist` の `NSCameraUsageDescription`。フォトライブラリ: `NSPhotoLibraryUsageDescription`。

## テスト

* テストアプリの Bundle ID をバインドし、実際の `appId` / `appKey` または `licenseToken` を使います。プレースホルダ文字列は認証イベント `1` / `101` を引き起こします。
* 静止画（`FBFrameTypeImage` + `createWithUIImage:`）とリアルタイム（`FBFrameTypeVideo`）の両方をカバーします。
* setter が `FBErrorCode_Success` を返すことをアサートします。
