All Products
Search
Document Center

ApsaraVideo Live:Integrate Queen SDK for iOS

Last Updated:Dec 22, 2023

Queen SDK is a smart retouching SDK developed by the video cloud team of Alibaba. This SDK provides a wide range of features including image retouching, face retouching, chroma key, stickers, makeup, gesture recognition, body shaping, hairdressing, and augmented reality (AR) writing. You can use these features in live streaming, video conferencing, and short video production scenarios. This topic describes how to integrate and use Queen SDK for iOS to implement face retouching effects. This topic also provides sample code and API references of Queen SDK for iOS.

Prerequisites

A development environment is set up. The following table describes the requirements for the development environment.

Item

Requirement

iOS

iOS 9.0 or later.

macOS High Sierra

macOS High Sierra 10.13 or later.

Xcode

Xcode 9.0 or later. To download Xcode, visit Mac App Store.

iOS device

Mobile devices that adopt the ARMv7 or ARM64 architecture, such as iPad and iPhone. Devices that run macOS and adopt the ARM64 architecture are not supported.

References

Item

References

SDK references

Sample project

Sample project

Demo project on GitHub

Demo project

Integration methods

You can integrate the SDK in pod or local mode based on your business requirements.

Pod mode

Sample code:

pod 'Queen', '6.7.0-official-pro' 

Local mode

  1. Download and decompress the Queen SDK package to obtain the following frameworks.

    queen.framework
    opencv2.framework
    Important

    opencv2.framework is not required for Basic Edition.

  2. Open Xcode and select your project target. On the General tab, add the preceding frameworks in the Frameworks, Libraries, and Embedded Content section and set Embed to Embed & Sign for these frameworks.

  3. On the Build Settings tab of the project target, find ENABLE_BITCODE and set this parameter to NO.

  4. Add mnn.metallib from the obtained queen.framework file to the project directory. This step is required only for Ultimate Edition and Full Edition.

Configure the license

Obtain a license in advance. For information about how to obtain a license, see Obtain a license of Queen SDK. After you obtain a license, perform the following steps to configure the LicenseKey and LicenseFile in the project.

Note
  • If you integrate Queen SDK of ApsaraVideo Live and the short video SDK of ApsaraVideo VOD at the same time, the two SDKs have the same LicenseKey and LicenseFile. You only need to configure the LicenseKey and LicenseFile once. Take note that the latest license file must be used.

  • If the SDK that you purchase is updated or needs to be renewed, you must update the license file. Perform the following steps to update the license file:

    1. Submit a request on the Create Application and Bind License page to obtain the latest license file. For more information, see Request a license.

    2. After you obtain the latest license file, perform the steps to configure the license.

Import the license file to the application project and add two keys to the Info.plist file.

  • The first key is AlivcLicenseKey, whose value is the value of the LicenseKey. Example: MoCTfuQ391Z01****8f8745e23c8a457a8ff8d5faedc1****.

  • The second key is AlivcLicenseFile, whose value is the path of the license file that is relative to the mainBundle. Example: AliVideoCert_164933454****.crt.

Sample code of Queen SDK

Note

If you upgrade Queen SDK from V1.X.X to V2.0.0 or later, take note of the following requirement:

In V2.0.0 and later versions, the authentication method for Queen SDK is changed. You must submit a request on the Create Application and Bind License page again to request a LicenseKey and LicenseFile, and specify Request License File in the title. After your request is received, Alibaba Cloud sends you the LicenseKey and LicenseFile within two business days. After you receive the LicenseKey and LicenseFile, complete the configuration as described in Configure the license.

- (void)initBeautyEngine
{
    // Initialize the configurations of QueenEngine.
    QueenEngineConfigInfo *configInfo = [QueenEngineConfigInfo new];

    // Specify whether to automatically set the rotation angle of images in specific scenarios, such as screen lock and image capture by a camera.
#if kEnableCustomSettingImgAngle
    configInfo.autoSettingImgAngle = NO;
#else
    configInfo.autoSettingImgAngle = YES;
#endif

    // Specify the root directory for resources.
    NSString *bundlPath = [[NSBundle mainBundle] bundlePath];
    configInfo.resRootPath = [bundlPath stringByAppendingString:@"/res"];

    // Initialize QueenEngine.
    self.beautyEngine = [[QueenEngine alloc] initWithConfigInfo:configInfo];

    [self testBaseFaceBeauty];
    [self testAdvancedFaceBeauty];
    [self testFaceMakeup];
    [self testFaceShape];
   [self testBodyShape];
    [self testFilter];
    [self testSticker];
    [self testGreenScreenOrBlueScreenCutout];
   [self testAutoFilter];
   [self testGestureDetect];
//  [self testBackgroundCutout];
//  [self testDebug];
}
- (void)testBaseFaceBeauty
{
    // Enable skin smoothing and image sharpening.
    // The third parameter specifies the basic retouching mode. If you set this parameter to kBMSkinBuffing_Natural, the retouching effect is more natural and more details are retained. If you set this parameter to kQueenBeautyFilterModeSkinBuffing_Strong, the effect is more exaggerated and more details are removed. 
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeSkinBuffing enable:YES mode:kQueenBeautyFilterModeSkinBuffing_Natural];

    // Set the level of skin smoothing.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsSkinBuffing value:0.5f];
    // Set the level of image sharpening.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsSharpen value:0.5f];

    // Enable skin whitening.
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeSkinWhiting enable:YES];

    // Set the level of skin whitening.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsWhitening value:0.5f];
}

- (void)testAdvancedFaceBeauty
{
    // Enable advanced retouching.
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeFaceBuffing enable:YES];

    // Set the level of eye bags removal.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsPouch value:0.5f];
    // Set the level of nasolabial folds removal.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsNasolabialFolds value:0.5f];
    // Set the level of teeth whitening.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsWhiteTeeth value:0.5f];
    // Set the level of lipstick effects.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsLipstick value:0.5f];
    // Set the level of blush effects.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsBlush value:0.5f];
    // Set the color of lipstick.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsLipstickColorParam value:0.1f];
    // Set the saturation of lipstick.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsLipstickGlossParam value:0.5f];
    // Set the brightness of lipstick.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsLipstickBrightnessParam value:0.5f];
    // Set the level of eye brightening.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsBrightenEye value:0.5f];
    // Set the level of rosy cheeks.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsSkinRed value:0.5f];
    // Set the level of wrinkles removal.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsWrinkles value:0.2f];
    // Set the level of skin brightening.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsBrightenFace value:0.2f];
}

- (void)testSkinHSV
{
    // Enable the HSV color model.
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeHSV enable:YES];

    // Set the level of saturation.
    [self.queenEngine setQueenBeautyParams:kQueenBeautyParamsHSVSaturation value:0.2f];
    // Set the level of contrast.
    [self.queenEngine setQueenBeautyParams:kQueenBeautyParamsHSVContrast value:0.2f];
}

- (void)testFaceMosaicing
{
    // Enable the face pixelation effect.
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeFaceMosaicing enable:YES];

    // Set the level of pixelation.
    [self.queenEngine setQueenBeautyParams:kQueenBeautyParamsFaceMosaicing value:0.2f];
}

- (void)testFaceMakeup
{                                          
 
    // Enable makeup.
    // The third parameter specifies the makeup mode. This parameter takes effect only on eyebrows. If you set this parameter to BeautyFilterMode.kBMFaceMakeup_High, the deformation level of eyebrows is high. If you set this parameter to kQueenBeautyFilterModeFaceMakeup_Baseline,
       the deformation level of eyebrows is low.
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeMakeup enable:YES mode:kQueenBeautyFilterModeFaceMakeup_Baseline];;

    BOOL makeupWhole = true;
    if (makeupWhole)    
    {
    // Set makeup effects for the full face. The path of the resources can be an absolute path.
    [self.beautyEngine setMakeupWithType:kQueenBeautyMakeupTypeWhole paths:@[@"makeup/whole/huoli.2.31.png"] blendType:kQueenBeautyBlendLabMix];
   // Set the transparency of full face makeup effects. The value of the female parameter is YES/true. The effects for male makeup are still being optimized.
   [self.beautyEngine setMakeupAlphaWithType:kQueenBeautyMakeupTypeWhole female:YES alpha:1.0];
   }
   else
   {
   // Set partial makeup effects. If full face makeup is configured, the configuration for full face makeup becomes invalid after a partial makeup effect is set. Full face makeup and partial makeup effects cannot coexist, but all partial makeup effects can be applied at the same time. For full face makeup, you can set a single makeup material to apply makeup to the entire face but cannot adjust the details of each part of the face.
   // Set the highlight effect for the full face. The path of the resources can be an absolute path.
    [self.beautyEngine setMakeupWithType:kQueenBeautyMakeupTypeHighlight paths:@[@"makeup/highlight/highlight.2.12.png"] blendType:kQueenBeautyBlendOverlay];
   // Set the transparency of the highlight effect. The value of the female parameter is YES/true. The effect for male makeup is still being optimized.
   [self.beautyEngine setMakeupAlphaWithType:kQueenBeautyMakeupTypeHighlight female:YES alpha:0.4];
   // Set the colored eye contacts effect. The path of the resources can be an absolute path.
   [self.beautyEngine setMakeupWithType:kQueenBeautyMakeupTypeEyeball paths:@[@"makeup/eyeball/milanda.2.1.png"] blendType:kQueenBeautyBlendLighten];
   // Set the transparency of the colored eye contacts effect. The value of the female parameter is YES/true. The effect for male makeup is still being optimized.
   [self.beautyEngine setMakeupAlphaWithType:kQueenBeautyMakeupTypeEyeball female:YES alpha:1.0];
   // Set the lipstick effect. The path of the resources can be an absolute path.
   [self.beautyEngine setMakeupWithType:kQueenBeautyMakeupTypeMouth paths:@[@"makeup/mouth_wumian/standout.2.31.png"] blendType:kQueenBeautyBlendLabMix];
   // Set the transparency of the lipstick effect. The value of the female parameter is YES/true. The effect for male makeup is still being optimized.
   [self.beautyEngine setMakeupAlphaWithType:kQueenBeautyMakeupTypeMouth female:YES alpha:0.5];
   // Set the aegyo-sal effect. Built-in materials are used and custom materials are not supported.
   [self.beautyEngine setMakeupWithType:kQueenBeautyMakeupTypeWocan paths:@[@"makeup/wocan.png"] blendType:kQueenBeautyBlendCurve];
   // Set the transparency of the aegyo-sal effect. The value of the female parameter is YES/true. The effect for male makeup is still being optimized.
   [self.beautyEngine setMakeupAlphaWithType:kQueenBeautyMakeupTypeWocan female:YES alpha:0.2];
   // Set the eyebrow effect. The path of the resources can be an absolute path.
   [self.beautyEngine setMakeupWithType:kQueenBeautyMakeupTypeEyeBrow paths:@[@"makeup/eyebrow/biaozhunmei.2.31.png"] blendType:kQueenBeautyBlendLabMix];
   // Set the transparency of the eyebrow effect. The value of the female parameter is YES/true. The effect for male makeup is still being optimized.
   [self.beautyEngine setMakeupAlphaWithType:kQueenBeautyMakeupTypeEyeBrow female:YES alpha:0.6];
    // Set the blush effect. The path of the resources can be an absolute path.
   [self.beautyEngine setMakeupWithType:kQueenBeautyMakeupTypeBlush paths:@[@"makeup/blush/weixun.2.31.png"] blendType:kQueenBeautyBlendLabMix];
   // Set the transparency of the blush effect. The value of the female parameter is YES/true. The effect for male makeup is still being optimized.
   [self.beautyEngine setMakeupAlphaWithType:kQueenBeautyMakeupTypeBlush female:YES alpha:0.8];
    // Set the eye shadow effect. The path of the resources can be an absolute path.
   [self.beautyEngine setMakeupWithType:kQueenBeautyMakeupTypeEyeShadow paths:@[@"makeup/eyeshadow/naichazong.2.31.png"] blendType:kQueenBeautyBlendLabMix];
    // Set the transparency of the eye shadow effect. The value of the female parameter is YES/true. The effect for male makeup is still being optimized.
   [self.beautyEngine setMakeupAlphaWithType:kQueenBeautyMakeupTypeEyeShadow female:YES alpha:0.7];
    // Set the eyeliner effect. The path of the resources can be an absolute path.
   [self.beautyEngine setMakeupWithType:kQueenBeautyMakeupTypeEyeliner paths:@[@"makeup/eyeliner_292929/wenrou.2.31.png"] blendType:kQueenBeautyBlendLabMix];
    // Set the transparency of the eyeliner effect. The value of the female parameter is YES/true. The effect for male makeup is still being optimized.
   [self.beautyEngine setMakeupAlphaWithType:kQueenBeautyMakeupTypeEyeliner female:YES alpha:0.5];
    // Set the eyelash effect. The path of the resources can be an absolute path.        [self.beautyEngine setMakeupWithType:kQueenBeautyMakeupTypeEyelash paths:@[@"makeup/eyelash/yesheng.2.31.png"] blendType:kQueenBeautyBlendLabMix];
    // Set the transparency of the eyelash effect. The value of the female parameter is YES/true. The effect for male makeup is still being optimized.
        [self.beautyEngine setMakeupAlphaWithType:kQueenBeautyMakeupTypeEyelash female:YES alpha:0.5];
    }
    
//    // Clear all makeup effects.
//    [self.beautyEngine resetAllMakeupType];
    
// // Disable makeup effects.
//    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeMakeup enable:NO];

/*
We recommend that you use mixed makeup. You can adjust the details of each part of the face. The following types of mixed makeup are provided:    
1. Tipsy makeup:
     For eye shadow, the path is makeup/eyeshadow/naichazong.2.31.png and the transparency is 0.7. 
     For eyelash, the path is makeup/eyelash/yesheng.2.31.png and the transparency is 0.5. 
     For blush, the path is makeup/blush/weixun.2.31.png and the transparency is 0.8. 
     For eyeliner, the path is makeup/eyeliner_292929/wenrou.2.31.png and the transparency is 0.5. 
     For lipstick, the path is makeup/mouth_wumian/standout.2.31.png and the transparency is 0.5. 
     For highlight, the path is makeup/highlight/highlight.2.12.png and the transparency is 0.4. 
2. Freckle makeup:
     For eye shadow, the path is makeup/eyeshadow/taohuafen.2.31.png and the transparency is 0.7. 
     For eyelash, the path is makeup/eyelash/yesheng.2.31.png and the transparency is 0.5. 
     For blush, the path is makeup/blush/cool.2.31.png and the transparency is 0.8. 
     For eyeliner, the path is makeup/eyeliner_292929/guima.2.31.png and the transparency is 0.5. 
     For lipstick, the path is makeup/mouth_yaochun/nanguase.2.31.png and the transparency is 0.5. 
     For highlight, the path is makeup/highlight/highlight.2.12.png and the transparency is 0.4.    
3. Lively makeup:
     For eye shadow, the path is makeup/eyeshadow/tianchengse.2.31.png and the transparency is 0.7. 
     For eyelash, the path is makeup/eyelash/lingdong.2.31.png and the transparency is 0.5. 
     For blush, the path is makeup/blush/luori.2.31.png and the transparency is 0.8. 
     For eyeliner, the path is makeup/eyeliner_292929/qizhi.2.31.png and the transparency is 0.5. 
     For lipstick, the path is makeup/mouth_yaochun/nanguase.2.31.png and the transparency is 0.5. 
     For highlight, the path is makeup/highlight/highlight.2.12.png and the transparency is 0.4.    
4. Nightclub makeup:
     For eye shadow, the path is makeup/eyeshadow/yeqiangwei.2.31.png and the transparency is 0.7. 
     For eyelash, the path is makeup/eyelash/zhixing.2.31.png and the transparency is 0.5. 
     For blush, the path is makeup/blush/shaonv.2.31.png and the transparency is 0.8. 
     For eyeliner, the path is makeup/eyeliner_292929/wenrou.2.31.png and the transparency is 0.5. 
     For lipstick, the path is makeup/mouth_zirun/zhenggongse.2.31.png and the transparency is 0.5. 
     For highlight, the path is makeup/highlight/highlight.2.12.png and the transparency is 0.4.
*/
}

- (void)testFaceShape
{
    // Enable face shaping.
    // The third parameter specifies the face shaping mode. Valid values: kQueenBeautyFilterModeFaceShape_Baseline, kQueenBeautyFilterModeFaceShape_Main, 
       kQueenBeautyFilterModeFaceShape_High, and kQueenBeautyFilterModeFaceShape_Max, with the deformation level increased in sequence.
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeFaceShape enable:YES mode:kQueenBeautyFilterModeFaceShape_Main];

    // Set the level of big eyes.
    [self.beautyEngine setFaceShape:kQueenBeautyFaceShapeTypeBigEye value:1.0f];
    // Set the level of hairline.
    [self.beautyEngine setFaceShape:kQueenBeautyFaceShapeTypeHairLine value:1.0f];
    // Set the level of smiling.
    [self.beautyEngine setFaceShape:kQueenBeautyFaceShapeTypeSmile value:1.0f];
}

- (void)testBodyShape
{
    // Enable face shaping.
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeBodyShape enable:YES];
    // Set the level of leg lengthening.
    [self.beautyEngine setFaceShape:kQueenBeautyBodyShapeTypeLongLag value:1.0f];
    //    // Set the level of head size reduction.
    //    [self.beautyEngine setFaceShape:kQueenBeautyBodyShapeTypeSmallHead value:1.0f];
}

- (void)testFilter
{
    // Enable filters.
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeLUT enable:YES];

    // Specify the filter to use. The path of the resource can be an absolute path.
    [self.beautyEngine setLutImagePath:@"lookups/ly1.png"];
    // Set the level of filters.
    [self.beautyEngine setQueenBeautyParams:kQueenBeautyParamsLUT value:0.8f];
}

- (void)testSticker
{
    // Add a sticker. The path of the resources can be an absolute path.
        [self.beautyEngine addMaterialWithPath:@"sticker/1"];
//    // Add another sticker. The stickers are overlaid from bottom to top.
//    [self.beautyEngine addMaterialWithPath:@"sticker/2"];
//    // Remove a sticker.
//    [self.beautyEngine removeMaterialWithPath:@"sticker/1"];
//    [self.beautyEngine removeMaterialWithPath:@"sticker/2"];
}

- (void)testGreenScreenOrBlueScreenCutout
{
    // Enable green screen for chroma key.
    NSString *backgroundImgPath = @"background/red.png";// The path of the resources can be an absolute path.
    BOOL enableBlue = NO;
    float threshold = 0;
    BOOL autoThreshold = YES;
    [self.beautyEngine setGreenScreen:backgroundImgPath blueScreenEnabled:enableBlue threshold:threshold autoThresholdEnabled:autoThreshold];

//    // Enable blue screen for chroma key.
//    enableBlue = YES;
//    [self.beautyEngine setGreenScreen:backgroundImgPath blueScreenEnabled:enableBlue threshold:threshold autoThresholdEnabled:autoThreshold];

//    // Disable chroma key.
//    [self.beautyEngine setGreenScreen:nil blueScreenEnabled:enableBlue threshold:threshold autoThresholdEnabled:autoThreshold];
}

- (void)testBackgroundCutout
{
// Before you enable background replacement, you can specify the performance mode based on your business requirements. The supported performance modes include Auto Mode, Best Quality Mode, Balance Mode, and Best Performance Mode. If you do not configure this parameter, Auto Mode is used by default.
// [self.beautyEngine setSegmentPerformanceMode:kQueenSegmentPMAuto];

//    // Enable background bokeh.
//    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeBackgroundProcess enable:YES];
//    // After you enable background bokeh, the background is blurred by default. You can use the following API operation to configure a transparent background. This is suitable for scenarios in which the output is used as a foreground and the background is synthesized.
//    [self.beautyEngine setSegmentBackgroundProcessType:kQueenBackgroundTransparent];
//    // Disable background bokeh.
//    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeBackgroundProcess enable:NO];
//
      NSString *backgroundResPath = @"background/static_changlang";// The path of the resources can be an absolute path.
      // Replace the background with a new static image. A resource cannot be added twice.
      [self.beautyEngine addMaterialWithPath:backgroundResPath];
//    // Remove the added background image.
//    [self.beautyEngine removeMaterialWithPath:backgroundResPath];
}

- (void)testAutoFilter
{
     // Enable intelligent dynamic optimization.
     [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeAutoFilter enable:YES];
    // Disable intelligent dynamic optimization.
     [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeAutoFilter enable:NO];
}
- (void)testGestureDetect
{
    // Enable gesture detection.
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeHandGestureDetect enable:YES];
//   // Disable gesture detection.
//   [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeHandGestureDetect enable:NO];
    // Set the proxy.    self.beautyEngine.delegate = self;
}
- (void)testSportDetect
{
    // Enable movement detection.
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeBodyDetect enable:YES];
    // Clear the movement count.
    [self.beautyEngine clearBodySportCount];
    // Set the types of movements that need to be detected and counted. 0 indicates posture recognition, 1 indicates rope jumping, 2 indicates jumping jack, 3 indicates squat, 4 indicates arm circle, 5 indicates diamond stretch, 6 indicates chest stretch, 7 indicates sit-up, 8 indicates push-up, and 9 indicates kneeling push-up.
    [self.beautyEngine setBodyDetectSportType:0];
    //    // Disable movement detection.
    //    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeBodyDetect enable:NO];

    // Set the proxy.
    self.beautyEngine.delegate = self;
}

- (void)queenEngine:(QueenEngine *)engine didDetectBodyInfo:(QEBodyInfoData *)bodyInfoData
{
    if (bodyInfoData.bodySportType <= 0)
    {
        /*
         {{1, Normal}, // Standing upright.
         {2, HandsUp}, // Raising both hands.
         {3, HandsOnHead}, // Hand heart or touching head.
         {4, LHandUp}, // Raising left hand.
         {5, RHandUp}, // Raising right hand.
         {6, HandLeft}, // Turning left 1.
         {7, HandRight}, // Turning right 1.
         {8, DaShape}, // Full body extension.
         {9, HandLeft2},// Turning left 2 with arms akimbo.
         {10, HandRight2},// Turning right 2 with arms akimbo.
         {11, SuperLeft}, // Superman pose towards left.
         {12, SuperRight}, // Superman pose towards right.
         {13, Akimbo}} // Arms akimbo.
         */
        NSLog(@"Posture recognized: %ld", (long)bodyInfoData.bodyPoseType);
    }
    else
    {
        NSLog(@"Movement recognized: %ld. Count: %ld.", (long)bodyInfoData.bodySportType, (long)bodyInfoData.sportCount);
    }
}
- (void)testReHairColor
{
    // Enable hair color try-on.
    [self.beautyEngine setQueenBeautyType:kQueenBeautyTypeHairColor enable:YES];

    // Configure hair color try-on.
    [self.beautyEngine setHairColorWithRed:0.3137254901960784
              withGreen:0.3137254901960784
              withBlue:0.6274509803921569];
/* 
* Reference colors:
* ('blue', [0.3137254901960784, 0.3137254901960784, 0.6274509803921569]) 
* ('purple', [0.6078431372549019, 0.35294117647058826, 0.6274509803921569]) 
* ('sky', [0.3333333333333333, 0.5490196078431373, 0.5490196078431373]) 
* ('yellow', [0.6470588235294118, 0.5294117647058824, 0.35294117647058826]) 
* ('green', [0.37254901960784315, 0.5882352941176471, 0.3137254901960784]) 
* ('original', [0.39215686274509803, 0.3333333333333333, 0.3137254901960784]) 
* ('red', [0.5098039215686274, 0.27450980392156865, 0.27450980392156865]) 
*/
}

- (void)testARWriting
{
    // Enable AR-powered in-air writing.
    [self.beautyEngine setARWriting:YES mode:0];
}

- (void)testDebug
{
    // Specify whether to show facial traits for recognition.
    [self.beautyEngine showFaceDetectPoint:YES];
    // Specify whether to show the triangulation information for makeup.
    [self.beautyEngine showMakeupLine:YES];
    // Specify whether to show hand traits for recognition.
   [self.beautyEngine showHandDetectPoint:YES];
}

- (CVPixelBufferRef)getProcessedPixelBufferRefWithCurrentPixelBufferRef:(CVPixelBufferRef)pixelBufferRef
{
    if (self.beautyEngine && pixelBufferRef)
    {
        QEPixelBufferData *bufferData = [QEPixelBufferData new];
        bufferData.bufferIn = pixelBufferRef;
        bufferData.bufferOut = pixelBufferRef;
#if kEnableCustomSettingImgAngle
        bufferData.inputAngle = self.cameraRotate; // Specify the rotation angle of the input frame images. Otherwise, facial recognition fails. If you do not obtain the rotation angle of the input frame images, set this parameter in the same manner in which you set the cameraRotate parameter.
        bufferData.outputAngle = self.cameraRotate; // Set this parameter to the same value as the inputAngle parameter.
#endif
        // Process the input frame images and export the processed frame images.
        kQueenResultCode resultCode = [self.beautyEngine processPixelBuffer:bufferData];// Use the same thread to execute this method.
        if (resultCode == kQueenResultCodeOK && bufferData.bufferOut)
        {
            return bufferData.bufferOut;
        }
        else if (resultCode == kQueenResultCodeInvalidLicense)
        {
            NSLog(@"License authentication failed.");
        }
        else if (resultCode == kQueenResultCodeInvalidParam)
        {
            NSLog(@"The parameter is invalid.");
        }
        else if (resultCode == kQueenResultCodeNoEffect)
        {
            NSLog(@"No effects are enabled.");
        }
        return pixelBufferRef;
        }
    else
       {
        return pixelBufferRef;
       }
}

- (void)captureReset
    {
    if (self.beautyEngine)
    {
        // Release QueenEngine. Make sure that the current thread is the same as the thread that is used to execute the processPixelBuffer method.
        [self.beautyEngine destroyEngine];
        self.beautyEngine = nil;
    }
}

- (void)captureBegin
{
#if kEnableCustomSettingImgAngle
    [self startRetainCameraRotate];
#endif
}

- (void)captureEnd
{
#if kEnableCustomSettingImgAngle
    [self stopRetainCameraRotate];
#endif
}

#pragma mark - QueenEngineDelegate

- (void)queenEngine:(QueenEngine *)engine didDetectGesture:(QEGestureData *)gestureData
{
    NSLog(@"Gesture type: %ld, Movement type: %d", (long)gestureData.gesture, gestureData.action);
}

Sample code for data and texture segmentation

/**
The callback for textures processed by QueenEngine.
*/
- (int)onProcessTexture:(int)texture textureWidth:(int)width textureHeight:(int)height
{
    if (self.pushConfig.beautyOn && nil != self.queenEngine) {
        QETextureData* textureData = [[QETextureData alloc] init];
        textureData.inputTextureID = texture;
        textureData.width = width;
        textureData.height = height;
        kQueenResultCode result = [self.beautyEngine processTexture:textureData];
        if (result != kQueenResultCodeOK) {
            NSLog(@"queen beauty processTexture error. code: %lu", result);
        }
        return textureData.outputTextureID;
    }
    return texture;
}

/**
The callback for detections processed by QueenEngine.
*/
- (long)onDetectorProcessData:(long)data w:(int)w h:(int)h rotation:(int)rotation format:(int)format
{
    if (self.pushConfig.beautyOn && nil != self.queenEngine) {
        [self.beautyEngine updateInputDataAndRunAlg:(uint8_t*)data
                                     withImgFormat:(kQueenImageFormat)(format)
                                         withWidth:w
                                        withHeight:h
                                        withStride:0
                                    withInputAngle:rotation
                                   withOutputAngle:rotation
                                      withFlipAxis:0];
    }
    return data;
}

/**
The callback for destroying QueenEngine.
*/
- (void)onDestory
{
    if (nil != self.beautyEngine) {
        [self.beautyEngine destroyEngine];
        self.beautyEngine = nil;
    }
}

Sample code for dynamic download

// If the SDK that you download does not have a built-in model, you must download the model before you can initialize QueenEngine.
- (void)checkModelsAndInitQueenEngine
{
    // Set the proxy for the resource manager.
    [QueenMaterial sharedInstance].delegate = self;

    // Determine whether you need to download the model.
    if (![[QueenMaterial sharedInstance] requestMaterial:kQueenMaterialModel])
    {
        // If you do not need to download the model, you can directly initialize the engine.
        [self initBeautyEngine];
    }
}

// Download the extended resources. The following code uses a sticker as an example.
- (void)downloadExtraResource
{
    // Set the proxy for the resource manager.
    [QueenMaterial sharedInstance].delegate = self;

    // Determine whether you need to download the sticker.
    if (![[QueenMaterial sharedInstance] requestMaterial:kQueenMaterialModel])
    {
        // If you do not need to download the sticker, directly obtain the resource directory.
        NSString *stickerResPath = [[QueenMaterial sharedInstance] getMaterialPath:kQueenMaterialSticker];
        NSLog(@"stickers Path:%@ \n", stickerResPath);
    }
}

#pragma mark - QueenMaterialDelegate

- (void)queenMaterialOnReady:(kQueenMaterialType)type
{
    // The resource is downloaded.
    if (type == kQueenMaterialModel)
    {
        // The model is downloaded. Initialize the engine.
        [self initBeautyEngine];
    }
    else if (type == kQueenMaterialSticker)
    {
        // The sticker is downloaded. Obtain the resource directory.
        NSString *stickerResPath = [[QueenMaterial sharedInstance] getMaterialPath:kQueenMaterialSticker];
        NSLog(@"stickers Path:%@ \n", stickerResPath);
    }
}

- (void)queenMaterialOnProgress:(kQueenMaterialType)type withCurrentSize:(int)currentSize withTotalSize:(int)totalSize withProgess:(float)progress
{
    // The callback for download progress.
}

- (void)queenMaterialOnError:(kQueenMaterialType)type
{
    // The callback for a resource download error.
}