本文为您介绍Android端阿里云Queen SDK的接口文档、集成操作及简单使用示例,用于实现美颜特效功能。

前提条件

开发前的环境要求如下表所示。
类别 说明
系统版本 支持Android 4.3及以上版本。
Java版本 支持Java 1.7及以上版本。
API LEVEL 支持ANDROID SDK API LEVEL 18及以上版本。
Android Studio版本 支持Android Studio 2.3以上版本,下载Android Studio

参考资料

项目 链接
中文版接口文档说明
Sample示例工程 Sample示例工程

示例工程文件中,assets目录下包含Demo所有图片资源。

在GitHub上提供的Demo工程 Demo工程

目前提供接入范例包括:阿里云直播SDK、七牛直播SDK、腾讯云实时音视频SDK。

Maven方式集成SDK

  1. 在项目级build.gradle项目文件中添加阿里云Maven仓库。
    allprojects {
        repositories {
            google()
            jcenter()
            maven { url "https://maven.aliyun.com/repository/releases" }
        }
    }
  2. 在相应Android端SDK包的应用级build.gradle项目文件下,加入Queen依赖项。
    • 极简lite版本:
      implementation "com.aliyun.maliang.android:queen:1.4.0-official-lite"
    • 专业pro版本:
      implementation "com.aliyun.maliang.android:queen:1.4.0-official-pro"
    • 全功能full版本:
      implementation "com.aliyun.maliang.android:queen:1.4.0-official-full"

手动导入aar集成SDK

  1. 下载并解压SDK。下载地址请参见SDK下载
  2. 将解压SDK获得的.aar文件复制到工程的libs目录中。

使用示例

  • 创建QueenEngine实例,设置初始化纹理与视窗参数
    QueenEngine engine;
    try {
        // 传入Android.content.Context触发引擎的初始化
        // 第二个参数为true表示直接输出到当前OpenGL的显示区域
        engine = new QueenEngine(mContext,true);
    } catch (InitializationException e) {
        e.printStackTrace();
    }
    
    // 设置输入纹理,用于美颜流程的渲染
    // 第四个参数表示输入纹理是否为OES类型的纹理
    engine.setInputTexture(textureId, textureWidth, textureHeight, true);
    
    // 非必要步骤:获得美颜输出纹理,可以在用于其他扩展业务,如果需要按照输入纹理方向返回输出纹理,则在生成纹理和设置纹理的时候,将“保持纹理方向”参数设置为true
    Texture2D outTexture = engine.autoGenOutTexture(true);
    engine.updateOutTexture(outTexture.getTextureId(), textureWidth, textureHeight, true);
    
    // 设置视窗大小
    engine.setScreenViewport(0, 0, viewWidth, viewHeight);
    // 开启log日志打印调试模式
    engine.enableDebugLog();
  • 设置美白和基础美化功能参数
    • 美白
      // 美白开关
      engine.enableBeautyType(BeautyFilterType.kSkinWhiting, true);
      // 美白参数 [0,1]
      engine.setBeautyParam(
          BeautyParams.kBPSkinWhitening, 
          0.3f
      );
    • 基础美颜
      // 磨皮和锐化开关
      engine.enableBeautyType(BeautyFilterType.kSkinBuffing, true);
      // 磨皮 [0,1]
      engine.setBeautyParam(BeautyParams.kBPSkinBuffing, 0.6f);
      //  锐化 [0,1]
      engine.setBeautyParam(BeautyParams.kBPSkinSharpen, 0.2f);
  • 设置高级功能参数
    使用高级功能,如高级美颜、美型、美妆、滤镜、贴纸,需要调用执行算法。
    if (mUseTextureBuffer) { // 直接使用纹理数据执行算法
        engine.updateInputTextureBufferAndRunAlg(
                mCamera.inputAngle, mCamera.outAngle,
                mCamera.flipAxis, false);
    } else {
        // 输入帧图片流,
        engine.updateInputDataAndRunAlg(
            imageData, // 帧图片流
            ImageFormat.NV21, // 帧图片流格式
            imageWidth, // 帧图片宽度 
            imageHeight, // 帧图片高度
            0, // 用于检测的图像的跨度(以像素为单位),即每行的字节数, 默认情况下设为 0
            mCamera.inputAngle, // 当前输入帧图片需旋转的角度,计算方式参考Sample工程
            mCamera.outAngle, // 算法输出结果所需旋转的角度,计算方式参考Sample工程
            mCamera.flipAxis // 输出数据的xy轴翻转处理,0为不旋转,1为x轴翻转,2为y轴翻转
        );
    }
    • 高级美颜
      // 高级美颜开关
      engine.enableBeautyType(BeautyFilterType.kFaceBuffing, true);
      //  去除法令纹[0,1]
      engine.setBeautyParam(BeautyParams.kBPNasolabialFolds, 0.3f); 
      //祛眼袋[0,1]
      engine.setBeautyParam(BeautyParams.kBPPouch, 0.3f); 
      // 白牙[0,1]
      engine.setBeautyParam(BeautyParams.kBPWhiteTeeth, 0.2f); 
      // 滤镜美妆:口红[0,1]
      engine.setBeautyParam(BeautyParams.kBPLipstick, 0.2f); 
      // 滤镜美妆:腮红[0,1]
      engine.setBeautyParam(BeautyParams.kBPBlush, 0.2f);
      // 滤镜美妆:亮眼[0,1]
      engine.setBeautyParam(BeautyParams.kBPBrightenEye, 1.0f); 
      // 滤镜美妆:红润[0,1]
      engine.setBeautyParam(BeautyParams.kBPBlush, 1.0f);
      // 滤镜美妆:口红色相[-0.5,0.5],需配合饱和度、明度使用,参考颜色如下:土红(-0.125)、粉红(-0.1)、复古红(0.0)、紫红(-0.2)、正红(-0.08)、橘红(0.0)、紫色(-0.42)、橘色(0.125)、黄色(0.25)
      engine.setBeautyParam(BeautyParams.kBPLipstickColorParam, 0.0f);
      // 滤镜美妆:口红饱和度[0,1],需配合色相、明度使用,参考颜色如下:土红(0.25)、粉红(0.125)、复古红(1.0)、紫红(0.35)、正红(1.0)、橘红(0.35)、紫色(0.35)、橘色(0.25)、黄色(0.45)
      engine.setBeautyParam(BeautyParams.kBPLipstickGlossParam, 0.0f);
      // 滤镜美妆:口红明度[0,1],需配合色相、饱和度使用,参考颜色如下:土红(0.4)、粉红(0.0)、复古红(0.2)、紫红(0.0)、正红(0.0)、橘红(0.0)、紫色(0.0)、橘色(0.0)、黄色(0.0)
      engine.setBeautyParam(BeautyParams.kBPLipstickBrightnessParam, 1.0f);
      // 祛皱[0,1]
      engine.setBeautyParam(BeautyParams.kBPWrinkles, 0.2f);
      // 去暗沉[0,1]
      engine.setBeautyParam(BeautyParams.kBPBrightenFace, 0.2f);
    • 美型
      // 美型开关,其中第二个参数是功能开关,第三个参数为调试开关
      engine.enableBeautyType(BeautyFilterType.kFaceShape, true, false);
      /**
       * 美型参数:颧骨<br />
       * 参数范围:[0,1]
       */
      engine.updateFaceShape(FaceShapeType.typeCutCheek, 0.0f);
      /**
       * 美型参数:削脸<br />
       * 参数范围:[0,1]
       */
      engine.updateFaceShape(FaceShapeType.typeCutFace, 0.0f);
      /**
       * 美型参数:瘦脸<br />
       * 参数范围:[0,1]
       */
      engine.updateFaceShape(FaceShapeType.typeThinFace, 0.0f);
      /**
       * 美型参数:脸长<br />
       * 参数范围:[0,1]
       */
      engine.updateFaceShape(FaceShapeType.typeLongFace, 0.0f);
      /**
       * 美型参数:下巴缩短<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeLowerJaw, 0.0f);
      /**
       * 美型参数:下巴拉长<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeHigherJaw, 0.0f);
      /**
       * 美型参数:瘦下巴<br />
       * 参数范围:[0,1]
       */
      engine.updateFaceShape(FaceShapeType.typeThinJaw, 0.0f);
      /**
       * 美型参数:瘦下颌<br />
       * 参数范围:[0,1]
       */
      engine.updateFaceShape(FaceShapeType.typeThinMandible, 0.0f);
      /**
       * 美型参数:大眼<br />
       * 参数范围:[0,1]
       */
      engine.updateFaceShape(FaceShapeType.typeBigEye, 0.0f);
      /**
       * 美型参数:眼角1<br />
       * 参数范围:[0,1]
       */
      engine.updateFaceShape(FaceShapeType.typeEyeAngle1, 0.0f);
      /**
       * 美型参数:眼距<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeCanthus, 0.0f);
      /**
       * 美型参数:拉宽眼距<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeCanthus1, 0.0f);
      /**
       * 美型参数:眼角2<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeEyeAngle2, 0.0f);
      /**
       * 美型参数:眼睛高度<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeEyeTDAngle, 0.0f);
      /**
       * 美型参数:瘦鼻<br />
       * 参数范围:[0,1]
       */
      engine.updateFaceShape(FaceShapeType.typeThinNose, 0.0f);
      /**
       * 美型参数:鼻翼<br />
       * 参数范围:[0,1]
       */
      engine.updateFaceShape(FaceShapeType.typeNosewing, 0.0f);
      /**
       * 美型参数:鼻长<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeNasalHeight, 0.0f);
      /**
       * 美型参数:鼻头长<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeNoseTipHeight, 0.0f);
      /**
       * 美型参数:唇宽<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeMouthWidth, 0.0f);
      /**
       * 美型参数:嘴唇大小<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeMouthSize, 0.0f);
      /**
       * 美型参数:唇高<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeMouthHigh, 0.0f);
      /**
       * 美型参数:人中<br />
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typePhiltrum, 0.0f);
      /**
       * 美型参数:发际线
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeHairLine, 0.0f);
      /**
       * 美型参数:嘴角上扬(微笑)
       * 参数范围:[-1,1]
       */
      engine.updateFaceShape(FaceShapeType.typeSmile, 0.0f);
    • 美妆

      开启妆容

      // 第二个参数是开关,第三个参数是调试开关
      engine.enableBeautyType(BeautyFilterType.kMakeup, true, false);
      
      // 设置美妆素材
      // 第一个参数是美妆类型
      // 第二个参数是素材文件路径,基于assets的相对路径,如"/makeup/蜜桃妆.png",也可以是有读取权限的绝对路径
      // 第三个参数是素材与人脸的融合类型,第四个参数是保留参数
      engine.setMakeupImage(MakeupType.kMakeupWocan,
                            new String[]{""},   //目前采用内置素材,不支持定制  
                            BlendType.kBlendCurve, 15);
      /** 
      * 整妆的类型是kMakeupWhole,设置单个素材即可实现全脸上妆,但是无法调节各部位细节。
      * 升级至1.4.0的用户,建议采用组合妆来替换整妆的效果,可以调节各部分细节,下面提供几种组合妆的模式:
      * 1、糖果妆:高光(makeup/highlight/highlight.2.12.png, 透明度:0.4)、
           口红(makeup/mouth_yaochun/doushafen.2.31.png 透明度:0.5)、腮红(makeup/blush/shaonv.2.31.png 透明度:1.0)、
           眼影(makeup/eyeshadow/shaonvfen.2.31.png 透明度:0.8)、眼线(makeup/eyeliner_5B443E/guima.2.31.png 透明度:0.6)、
           睫毛(makeup/eyelash/yesheng.2.31.png 透明度:0.6)
      * 2、夜店妆:高光(makeup/highlight/highlight.2.12.png, 透明度:0.4)、
           口红(makeup/mouth_wumian/naiyoucheng.2.31.png 透明度:0.5)、腮红(makeup/blush/chulian.2.31.png 透明度:1.0)、
           眼影(makeup/eyeshadow/jiaotangzong.2.31.png 透明度:0.8)、眼线(makeup/eyeliner_5B443E/xiaoyemao.2.31.png 透明度:
           0.6)、睫毛(makeup/eyelash/huopo.2.31.png 透明度:0.6)
      * 3、复古妆:高光(makeup/highlight/highlight.2.12.png, 透明度:0.4)、
           口红(makeup/mouth_zirun/ningxiangzi.2.31.png 透明度:0.5)、腮红(makeup/blush/suyan.2.31.png 透明度:1.0)、
           眼影(makeup/eyeshadow/zhuanhongse.2.31.png 透明度:0.8)、眼线(makeup/eyeliner_5B443E/lingdong.2.31.png 透明度:
           0.6)、睫毛(makeup/eyelash/ziran.2.31.png 透明度:0.6)
      * 4、桃花妆:高光(makeup/highlight/highlight.2.12.png, 透明度:0.4)、
           口红(makeup/mouth_wumian/naiyoucheng.2.31.png 透明度:0.5)、腮红(makeup/blush/shaonv.2.31.png  透明度:1.0)、
           眼影(makeup/eyeshadow/ziranse.2.31.png 透明度:0.8)、眼线(makeup/eyeliner_5B443E/wenrou.2.31.png 透明度:0.6)、
           睫毛(makeup/eyelash/wugu.2.31.png 透明度:0.6)
      **/
      
      // 设置美妆素材透明度
      // 第二个参数是透明度,第三个参数是保留参数
      engine.setMakeupAlpha(MakeupType.kMakeupWocan, 0.6f, 0.3f);

      关闭妆容

      engine.setMakeupImage(MakeupType.kMakeupWocan, new String[], BlendType.kBlendCurve, 15);

      开启卧蚕

       // 第二个参数是开关,第三个参数是调试开关
      engine.enableBeautyType(BeautyFilterType.kMakeup, true, false);
      
      engine.setMakeupImage(MakeupType.kMakeupWocan,
                            new String[]{""},   //目前采用内置素材,不支持定制  
                            BlendType.kBlendCurve, 15);
      
      engine.setMakeupAlpha(MakeupType.kMakeupWocan, 0.6f, 0.3f);
      关闭卧蚕
      engine.setMakeupImage(MakeupType.kMakeupWocan, new String[], BlendType.kBlendCurve, 15);
    • 滤镜
      // 功能开关
      engine.enableBeautyType(BeautyFilterType.kLUT, true);
      // 设置滤镜资源路径,基于assets的相对路径,如“/lookups/lookup_1.png”,也可以是有读取权限的绝对路径
      engine.setFilter(lutResPath); 
      // 滤镜强度
      engine.setBeautyParam(BeautyParams.kBPLUT, 1.0f); 
    • 贴纸
      // 删除贴纸素材路径
      engine.removeMaterial(oldStickerResPath);
      // 添加贴纸素材路径,相同贴纸不能重复添加
      // 基于assets的相对路径,如"/sticker/baiyang",也可以是有读取权限的绝对路径
      engine.addMaterial(stickerResPath);
    • 蓝/绿幕抠图
      /**
       * 设置绿幕抠图参数
       * @param backgroundPath : 要替换的背景资源图文件地址,路径地址为"",则为关闭该项功能
       * @param blueScreenEnabled : 是否使用蓝幕,true为替换蓝幕背景,false则为替换绿幕背景
       * @param threshold 范围:【20,60】,默认建议取值30.    
       */
      engine.setGreenScreen(String backgroundPath, boolean blueScreenEnabled, float threshold);
    • 智能抠像
      // 删除背景素材路径
      engine.removeMaterial(oldBackgroundResPath);
      // 添加背景素材路径,相同贴纸不能重复添加
      // 基于assets的相对路径,如"/static/xiaomanyao",也可以是有读取权限的绝对路径
      engine.addMaterial(backgroundResPath);
      // 除了上述的替换背景之外,也可以直接开启背景虚化功能
      engine.enableBeautyType(BeautyFilterType.kBTBackgroundProcess, true);
  • 渲染
    // OES纹理的变换矩阵,通过SurfaceTexture获取
    float[] transformMatrix = new float[16];
    // 通过SurfaceTexture更新矩阵
    mSurfaceTexture.updateTexImage();
    mSurfaceTexture.getTransformMatrix(transformMatrix);
    
    // 渲染到当前窗口,如证书校验失败或者全部特效功能关闭,则SDK不会执行渲染操作
    int retCode = engine.renderTexture(transformMatrix);
    
    // 参考API文档
    // QUEEN_INVALID_LICENSE(-9),表示证书校验失败
    // QUEEN_NO_EFFECT(-10),表示全部特效功能关闭
    // 则需要业务方执行渲染,可参考Sample工程
    if (retCode == -9 || retCode == -10) {
        mFrameGlDrawer.draw(transformMatrix, mOESTextureId, true);
    }
  • 释放引擎
    // 释放引擎资源
    engine.release();

视频直播接入范例

以视频直播推流SDK V4.2.0接入为例,请参见以下步骤。

  1. 确保已开启直播配置项,允许预处理模式。
    mAliLiveConfig.customPreProcessMode = CUSTOM_MODE_VIDEO_PREPROCESS;
  2. 初始化QueenEngine。
    engine = new QueenEngine(this, false);
  3. 注册视频处理回调代理,获取纹理更新。
    public int onTextureInput(int inputTexture, int textureWidth, int textureHeight) {
        glThreadId = Thread.currentThread().getId();
    
        if (mMediaChainEngine == null || !isBeautyEnable) {
        return inputTexture;
            }
        updateSettings();
    
        int[] oldFboId = new int[1];
        GLES20.glGetIntegerv(GLES20.GL_FRAMEBUFFER_BINDING, 
    IntBuffer.wrap(oldFboId));
    
        mMediaChainEngine.setInputTexture(inputTexture, textureWidth, 
    textureHeight, false);
    
       //如果画面旋转的话,就需要重新创建设置大小
       if (lastTextureWidth != textureWidth || lastTextureHeight != textureHeight) 
    {
       if (mOutTexture2D != null) {
           mOutTexture2D.release();
           mOutTexture2D = null;
                }
       lastTextureWidth = textureWidth;
       lastTextureHeight = textureHeight;
       mMediaChainEngine.setScreenViewport(0, 0, textureWidth,
    textureHeight);
            }
    
       if (mOutTexture2D == null) {
           mOutTexture2D = mMediaChainEngine.autoGenOutTexture();
            }
    
       if (mOutTexture2D == null) {
           return inputTexture;
           }
    
       long now = SystemClock.uptimeMillis();
    
       boolean hasRunAlg = false;
       if (USE_FRAME_SYNCHRONIZED) {
           mMediaChainEngine.setInputFlip(Flip.kNone);
           if (outAngle == 90 || outAngle == 270) {// 右 out = 90 / 左 out = 270
               mMediaChainEngine.setRenderAndFaceFlip(Flip.kFlipY, Flip.kNone);
               mMediaChainEngine.updateInputTextureBufferAndRunAlg(360-outAngle, outAngle, Flip.kFlipY, false);
          } else { // 正 out = 180 / 倒立 out = 0               
               mMediaChainEngine.setRenderAndFaceFlip(Flip.kNone, Flip.kFlipY);               
               mMediaChainEngine.updateInputTextureBufferAndRunAlg(180-outAngle, 180-outAngle, Flip.kNone, false); 
          }
          hasRunAlg = true;
          } else if (mAlgNativeBufferPtr != 0) {
              mMediaChainEngine.updateInputNativeBufferAndRunAlg(mAlgNativeBufferPtr, 
              mAlgDataFormat, mAlgDataWidth, mAlgDataHeight, nAlgDataStride, 
              inputAngle, outAngle, flipAxis);
          hasRunAlg = true;
          }
    
              int retCode = mMediaChainEngine.render();
              isAlgDataRendered = true;
    
              Log.i(TAG, Thread.currentThread().getId() + " - " +"render : " + 
          (SystemClock.uptimeMillis()-now) + "ms, hasRunAlg: " + hasRunAlg + ", 
          textureW: " + textureWidth + ", textureH: " + textureHeight + ", outAngle: " +
          outAngle);
             if (retCode == -9 || retCode == -10) {
                 Log.d(TAG, "queen error code:" + retCode + ",please ensure license valid");
                 return inputTexture;
           }
    
           GLES20.glBindFramebuffer(GL_FRAMEBUFFER, oldFboId[0]);
    
           return mOutTexture2D.getTextureId();
       }