Android Codec2 Filter 算法模块开发指南

Android Codec2 Filter 算法模块开发指南

目录

  1. 概述
  2. 架构设计
  3. 算法模块封装流程
  4. [Plugin 实现详解](#Plugin 实现详解)
  5. [JNI 调用流程](#JNI 调用流程)
  6. 完整示例
  7. 调试与优化
  8. 常见问题

概述

https://cs.android.com/android/platform/superproject/+/master:frameworks/av/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp

【个人见解】Codec2-Pipeline 和 GSteamer、SPF(QCOM ADSP框架)、各类AI推理网络(onnx qnn snpe ncnn mnn 等)pipeline 有异曲同工之处

本文档详细介绍如何基于 Android Codec2 Filter 框架开发自定义算法模块,包括算法封装、Plugin 实现以及 JNI或、JAVA侧 调用的完整流程。

核心概念

  • Codec2 Component: Android 多媒体框架的核心组件
  • Filter Plugin: 可插拔的滤镜插件机制
  • C2Component: Codec2 组件接口
  • FilterWrapper: 组件包装器,管理 filter 生命周期

架构设计

整体架构图

复制代码
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   Application   │    │   MediaCodec     │    │   Display       │
│                 │◄───│                  │◄───│                 │
└─────────────────┘    └──────────────────┘    └─────────────────┘
                                │
                                ▼
                       ┌──────────────────┐
                       │  FilterWrapper   │
                       │                  │
                       └──────────────────┘
                                │
                ┌───────────────┼───────────────┐
                ▼               ▼               ▼
        ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
        │   Decoder    │ │   Filter 1   │ │   Filter 2   │
        │              │ │              │ │              │
        └──────────────┘ └──────────────┘ └──────────────┘

数据流向

复制代码
Input Buffer → Decoder → Filter Chain → Output Buffer
                │           │
                ▼           ▼
           解码处理    算法处理(如:降噪、增强、转换)

算法模块封装流程

步骤 1: 定义算法接口

首先定义算法处理的核心接口:

cpp 复制代码
// AlgorithmInterface.h
#pragma once

#include <memory>
#include <vector>
#include <cstdint>

namespace myalgorithm {

// 算法配置参数
struct AlgorithmConfig {
    int width;
    int height;
    int format;  // 像素格式
    float strength;  // 处理强度
    bool enable_gpu;  // 是否使用 GPU 加速
};

// 算法处理结果
enum AlgorithmResult {
    SUCCESS = 0,
    ERROR_INVALID_INPUT = -1,
    ERROR_PROCESSING = -2,
    ERROR_UNSUPPORTED_FORMAT = -3,
};

// 算法处理接口
class IAlgorithmProcessor {
public:
    virtual ~IAlgorithmProcessor() = default;
    
    // 初始化算法
    virtual AlgorithmResult init(const AlgorithmConfig& config) = 0;
    
    // 处理单帧
    virtual AlgorithmResult process(
        const uint8_t* input_data,
        uint8_t* output_data,
        int stride) = 0;
    
    // 释放资源
    virtual void release() = 0;
    
    // 获取处理延迟
    virtual int getLatency() const = 0;
};

// 工厂函数
std::unique_ptr<IAlgorithmProcessor> createProcessor();

}  // namespace myalgorithm

步骤 2: 实现核心算法

实现具体的算法处理逻辑:

cpp 复制代码
// MyAlgorithmProcessor.cpp
#include "AlgorithmInterface.h"
#include <android-base/logging.h>
#include <chrono>

#ifdef USE_GPU
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#endif

namespace myalgorithm {

class MyAlgorithmProcessor : public IAlgorithmProcessor {
public:
    MyAlgorithmProcessor() = default;
    ~MyAlgorithmProcessor() override { release(); }

    AlgorithmResult init(const AlgorithmConfig& config) override {
        if (config.width <= 0 || config.height <= 0) {
            return ERROR_INVALID_INPUT;
        }
        
        config_ = config;
        
        // 初始化 CPU 处理
        if (!initCPU()) {
            return ERROR_PROCESSING;
        }
        
        // 如果启用 GPU,初始化 GPU 处理
        if (config.enable_gpu) {
            if (!initGPU()) {
                LOG(WARNING) << "GPU initialization failed, falling back to CPU";
                config_.enable_gpu = false;
            }
        }
        
        initialized_ = true;
        return SUCCESS;
    }

    AlgorithmResult process(
        const uint8_t* input_data,
        uint8_t* output_data,
        int stride) override {
        
        if (!initialized_ || !input_data || !output_data) {
            return ERROR_INVALID_INPUT;
        }
        
        auto start = std::chrono::high_resolution_clock::now();
        
        AlgorithmResult result;
        if (config_.enable_gpu) {
            result = processGPU(input_data, output_data, stride);
        } else {
            result = processCPU(input_data, output_data, stride);
        }
        
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
        last_process_time_ = duration.count();
        
        return result;
    }

    void release() override {
        if (initialized_) {
            releaseCPU();
            if (config_.enable_gpu) {
                releaseGPU();
            }
            initialized_ = false;
        }
    }

    int getLatency() const override {
        return last_process_time_;
    }

private:
    bool initCPU() {
        // CPU 处理初始化
        // 例如:分配临时缓冲区、初始化算法参数等
        temp_buffer_.resize(config_.width * config_.height * 4);
        return true;
    }

    bool initGPU() {
#ifdef USE_GPU
        // GPU 初始化逻辑
        // 创建 EGL 上下文、编译着色器等
        return initEGL() && initShaders();
#else
        return false;
#endif
    }

    AlgorithmResult processCPU(const uint8_t* input, uint8_t* output, int stride) {
        // CPU 算法处理实现
        // 示例:简单的图像增强算法
        
        for (int y = 0; y < config_.height; ++y) {
            for (int x = 0; x < config_.width; ++x) {
                int idx = y * stride + x;
                
                // 简单的亮度增强
                int pixel = input[idx];
                pixel = static_cast<int>(pixel * config_.strength);
                pixel = std::min(255, std::max(0, pixel));
                
                output[idx] = static_cast<uint8_t>(pixel);
            }
        }
        
        return SUCCESS;
    }

    AlgorithmResult processGPU(const uint8_t* input, uint8_t* output, int stride) {
#ifdef USE_GPU
        // GPU 处理实现
        // 使用 OpenGL ES 进行并行处理
        return processWithOpenGL(input, output, stride);
#else
        return ERROR_UNSUPPORTED_FORMAT;
#endif
    }

    void releaseCPU() {
        temp_buffer_.clear();
    }

    void releaseGPU() {
#ifdef USE_GPU
        // 释放 GPU 资源
        if (egl_context_ != EGL_NO_CONTEXT) {
            eglDestroyContext(egl_display_, egl_context_);
        }
#endif
    }

#ifdef USE_GPU
    bool initEGL() {
        // EGL 初始化代码
        egl_display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
        if (egl_display_ == EGL_NO_DISPLAY) {
            return false;
        }
        
        EGLint major, minor;
        if (!eglInitialize(egl_display_, &major, &minor)) {
            return false;
        }
        
        // 配置 EGL
        EGLint config_attribs[] = {
            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_NONE
        };
        
        EGLint num_configs;
        EGLConfig config;
        if (!eglChooseConfig(egl_display_, config_attribs, &config, 1, &num_configs)) {
            return false;
        }
        
        EGLint context_attribs[] = {
            EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL_NONE
        };
        
        egl_context_ = eglCreateContext(egl_display_, config, EGL_NO_CONTEXT, context_attribs);
        return egl_context_ != EGL_NO_CONTEXT;
    }

    bool initShaders() {
        // 着色器编译和链接
        const char* vertex_shader_source = 
            "attribute vec4 position;\n"
            "attribute vec2 texcoord;\n"
            "varying vec2 v_texcoord;\n"
            "void main() {\n"
            "    gl_Position = position;\n"
            "    v_texcoord = texcoord;\n"
            "}\n";
        
        const char* fragment_shader_source =
            "precision mediump float;\n"
            "varying vec2 v_texcoord;\n"
            "uniform sampler2D texture;\n"
            "uniform float strength;\n"
            "void main() {\n"
            "    vec4 color = texture2D(texture, v_texcoord);\n"
            "    color.rgb *= strength;\n"
            "    gl_FragColor = color;\n"
            "}\n";
        
        // 编译着色器代码...
        return compileShaders(vertex_shader_source, fragment_shader_source);
    }

    AlgorithmResult processWithOpenGL(const uint8_t* input, uint8_t* output, int stride) {
        // OpenGL 处理实现
        // 1. 创建纹理
        // 2. 上传数据
        // 3. 执行处理
        // 4. 读取结果
        return SUCCESS;
    }
#endif

private:
    AlgorithmConfig config_;
    bool initialized_ = false;
    std::vector<uint8_t> temp_buffer_;
    int last_process_time_ = 0;

#ifdef USE_GPU
    EGLDisplay egl_display_ = EGL_NO_DISPLAY;
    EGLContext egl_context_ = EGL_NO_CONTEXT;
    GLuint program_ = 0;
    GLuint input_texture_ = 0;
    GLuint output_texture_ = 0;
#endif
};

std::unique_ptr<IAlgorithmProcessor> createProcessor() {
    return std::make_unique<MyAlgorithmProcessor>();
}

}  // namespace myalgorithm

步骤 3: 封装为 Codec2 Component

将算法封装为 Codec2 组件:

cpp 复制代码
// MyAlgorithmC2Component.h
#pragma once

#include <C2Component.h>
#include <C2Config.h>
#include "AlgorithmInterface.h"
#include <memory>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <thread>

class MyAlgorithmC2Component : public C2Component,
                               public std::enable_shared_from_this<MyAlgorithmC2Component> {
public:
    MyAlgorithmC2Component(c2_node_id_t id, 
                          const std::shared_ptr<C2ReflectorHelper> &reflector);
    ~MyAlgorithmC2Component() override;

    // C2Component 接口
    c2_status_t setListener_vb(const std::shared_ptr<Listener> &listener, 
                               c2_blocking_t mayBlock) override;
    c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override;
    c2_status_t announce_nb(const std::vector<C2WorkOutline> &) override;
    c2_status_t flush_sm(flush_mode_t mode, 
                        std::list<std::unique_ptr<C2Work>>* const flushedWork) override;
    c2_status_t drain_nb(drain_mode_t mode) override;
    c2_status_t start() override;
    c2_status_t stop() override;
    c2_status_t reset() override;
    c2_status_t release() override;
    std::shared_ptr<C2ComponentInterface> intf() override;

private:
    // 内部状态
    enum State {
        STOPPED,
        RUNNING,
        RELEASED,
        STARTING,
        STOPPING,
        RESETTING,
        RELEASING,
    };

    // 处理线程函数
    void processLoop();
    c2_status_t processWork(std::unique_ptr<C2Work> &work);
    
    // Buffer 管理
    c2_status_t allocateOutputBuffer(std::shared_ptr<C2GraphicBlock> *block);
    c2_status_t processGraphicBuffer(const C2GraphicView &srcView, 
                                    C2GraphicView &dstView);
    
    // 状态管理
    State mState = STOPPED;
    std::mutex mStateMutex;
    
    // 工作队列
    std::mutex mQueueMutex;
    std::condition_variable mQueueCondition;
    std::list<std::unique_ptr<C2Work>> mQueue;
    
    // 处理线程
    std::thread mProcessThread;
    bool mThreadRunning = false;
    
    // 监听器
    std::shared_ptr<Listener> mListener;
    
    // 组件接口
    std::shared_ptr<C2ComponentInterface> mInterface;
    
    // 算法处理器
    std::unique_ptr<myalgorithm::IAlgorithmProcessor> mProcessor;
    
    // 配置参数
    int mWidth = 0;
    int mHeight = 0;
    int mStride = 0;
    C2PixelFormat mFormat = C2PixelFormat::YUV420;
    
    // Buffer 池
    std::shared_ptr<C2BlockPool> mBlockPool;
};

Plugin 实现详解

Plugin 架构

复制代码
┌─────────────────────────────────────────┐
│           FilterPlugin_V1               │
│  ┌─────────────────────────────────────┐│
│  │         ComponentStore              ││
│  │  ┌─────────────────────────────┐   ││
│  │  │    MyAlgorithmC2Component   │   ││
│  │  │                             │   ││
│  │  └─────────────────────────────┘   ││
│  └─────────────────────────────────────┘│
└─────────────────────────────────────────┘

完整 Plugin 实现

cpp 复制代码
// MyAlgorithmFilterPlugin.cpp
#include <C2Component.h>
#include <C2Config.h>
#include <FilterWrapper.h>
#include "MyAlgorithmC2Component.h"
#include <android-base/logging.h>
#include <cutils/properties.h>

// 组件 Store 实现
class MyAlgorithmComponentStore : public C2ComponentStore {
public:
    MyAlgorithmComponentStore() {
        // 注册组件
        registerComponent("my.algorithm.filter");
    }

    std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override {
        std::vector<std::shared_ptr<const C2Component::Traits>> components;
        
        auto traits = std::make_shared<C2Component::Traits>();
        traits->name = "my.algorithm.filter";
        traits->domain = C2Component::DOMAIN_VIDEO;
        traits->kind = C2Component::KIND_OTHER;
        traits->rank = 0x100;  // 设置优先级
        
        components.push_back(traits);
        return components;
    }

    std::shared_ptr<C2ComponentInterface> createComponentInterface(
            C2String name, c2_node_id_t id) override {
        if (name == "my.algorithm.filter") {
            auto reflector = std::make_shared<C2ReflectorHelper>();
            auto component = std::make_shared<MyAlgorithmC2Component>(id, reflector);
            return component->intf();
        }
        return nullptr;
    }

    c2_status_t createComponent(
            C2String name,
            std::shared_ptr<C2Component> *const component) override {
        if (name == "my.algorithm.filter") {
            auto reflector = std::make_shared<C2ReflectorHelper>();
            *component = std::make_shared<MyAlgorithmC2Component>(
                0, reflector);  // 使用默认 node_id
            return C2_OK;
        }
        return C2_NOT_FOUND;
    }

    c2_status_t query_sm(
            const std::vector<C2Param*> &stackParams,
            const std::vector<C2Param::Index> &heapParamIndices,
            std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
        // 查询 store 参数
        return C2_OK;
    }

    c2_status_t config_sm(
            const std::vector<C2Param*> &params,
            std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
        // 配置 store 参数
        return C2_OK;
    }

    std::vector<std::shared_ptr<const C2ParamDescriptor>> 
    querySupportedParams_nb() const override {
        // 返回支持的参数描述符
        return {};
    }

    c2_status_t querySupportedValues_sm(
            std::vector<C2FieldSupportedValuesQuery> &fields) const override {
        // 查询支持的字段值
        return C2_OK;
    }

private:
    void registerComponent(const std::string &name) {
        // 组件注册逻辑
    }
};

// Plugin 实现
class MyAlgorithmFilterPlugin : public FilterPlugin_V1 {
public:
    MyAlgorithmFilterPlugin() {
        mStore = std::make_shared<MyAlgorithmComponentStore>();
        LOG(INFO) << "MyAlgorithmFilterPlugin created";
    }

    ~MyAlgorithmFilterPlugin() override {
        LOG(INFO) << "MyAlgorithmFilterPlugin destroyed";
    }

    std::shared_ptr<C2ComponentStore> getComponentStore() override {
        return mStore;
    }

    bool describe(C2String name, Descriptor *desc) override {
        if (name == "my.algorithm.filter") {
            desc->inputFormat = { C2FormatYUV420 };
            desc->outputFormat = { C2FormatYUV420 };
            return true;
        }
        return false;
    }

    bool isFilteringEnabled(const std::shared_ptr<C2ComponentInterface> &intf) override {
        // 检查是否需要启用 filter
        
        // 1. 检查系统属性
        bool propEnabled = property_get_bool(
            "vendor.my.algorithm.filter.enable", true);
        if (!propEnabled) {
            return false;
        }
        
        // 2. 检查编码格式
        C2StreamMediaTypeSetting::input mediaType;
        c2_status_t err = intf->query_vb({&mediaType}, {}, C2_DONT_BLOCK, nullptr);
        if (err == C2_OK) {
            // 支持的编码格式
            if (mediaType.value == "video/avc" || 
                mediaType.value == "video/hevc" ||
                mediaType.value == "video/av01") {
                return true;
            }
        }
        
        // 3. 检查分辨率
        C2StreamPictureSizeInfo::input pictureSize;
        err = intf->query_vb({&pictureSize}, {}, C2_DONT_BLOCK, nullptr);
        if (err == C2_OK) {
            // 只处理特定分辨率范围的内容
            if (pictureSize.width >= 1280 && pictureSize.height >= 720) {
                return true;
            }
        }
        
        return false;
    }

    c2_status_t queryParamsForPreviousComponent(
            const std::shared_ptr<C2ComponentInterface> &intf,
            std::vector<std::unique_ptr<C2Param>> *params) override {
        // 如果需要向前一个组件查询参数,在这里实现
        // 例如:查询解码器支持的输出格式
        
        C2StreamPixelFormatInfo::output pixelFormat;
        c2_status_t err = intf->query_vb({&pixelFormat}, {}, C2_DONT_BLOCK, nullptr);
        if (err == C2_OK) {
            // 可以根据解码器输出格式调整 filter 参数
        }
        
        return C2_OK;
    }

private:
    std::shared_ptr<C2ComponentStore> mStore;
};

// C 接口导出
extern "C" {

int32_t GetFilterPluginVersion() {
    return 1;
}

void *CreateFilterPlugin() {
    return new MyAlgorithmFilterPlugin();
}

void DestroyFilterPlugin(void *plugin) {
    delete static_cast<MyAlgorithmFilterPlugin*>(plugin);
}

}

JNI 调用流程

JNI 架构

复制代码
┌─────────────────┐
│   Java/Kotlin   │
│   Application   │
└─────────────────┘
         │
         ▼
┌─────────────────┐
│   JNI Layer     │
│                 │
└─────────────────┘
         │
         ▼
┌─────────────────┐
│   Native C++    │
│   Codec2        │
└─────────────────┘
         │
         ▼
┌─────────────────┐
│   Filter Plugin │
│                 │
└─────────────────┘

JNI 接口定义

cpp 复制代码
// jni/MyAlgorithmFilter_jni.h
#pragma once

#include <jni.h>
#include <string>

#ifdef __cplusplus
extern "C" {
#endif

// 初始化算法 filter
JNIEXPORT jboolean JNICALL
Java_com_xiaomi_media_MyAlgorithmFilter_nativeInit(
    JNIEnv *env,
    jobject thiz,
    jint width,
    jint height,
    jfloat strength);

// 处理 buffer
JNIEXPORT jboolean JNICALL
Java_com_xiaomi_media_MyAlgorithmFilter_nativeProcess(
    JNIEnv *env,
    jobject thiz,
    jobject inputBuffer,
    jobject outputBuffer,
    jint stride);

// 释放资源
JNIEXPORT void JNICALL
Java_com_xiaomi_media_MyAlgorithmFilter_nativeRelease(
    JNIEnv *env,
    jobject thiz);

// 获取处理延迟
JNIEXPORT jint JNICALL
Java_com_xiaomi_media_MyAlgorithmFilter_nativeGetLatency(
    JNIEnv *env,
    jobject thiz);

// 设置参数
JNIEXPORT jboolean JNICALL
Java_com_xiaomi_media_MyAlgorithmFilter_nativeSetParameter(
    JNIEnv *env,
    jobject thiz,
    jstring key,
    jstring value);

#ifdef __cplusplus
}
#endif

JNI 实现(system uid签名)

cpp 复制代码
// jni/MyAlgorithmFilter_jni.cpp
#include "MyAlgorithmFilter_jni.h"
#include "AlgorithmInterface.h"
#include <android-base/logging.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>

// 全局算法处理器实例
static std::unique_ptr<myalgorithm::IAlgorithmProcessor> g_processor;

// Java 类名
static const char* const kClassPathName = "com/xiaomi/media/MyAlgorithmFilter";

// JNI 方法表
static const JNINativeMethod sMethods[] = {
    {"nativeInit", "(IIF)Z", (void*)Java_com_xiaomi_media_MyAlgorithmFilter_nativeInit},
    {"nativeProcess", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;I)Z", 
     (void*)Java_com_xiaomi_media_MyAlgorithmFilter_nativeProcess},
    {"nativeRelease", "()V", (void*)Java_com_xiaomi_media_MyAlgorithmFilter_nativeRelease},
    {"nativeGetLatency", "()I", (void*)Java_com_xiaomi_media_MyAlgorithmFilter_nativeGetLatency},
    {"nativeSetParameter", "(Ljava/lang/String;Ljava/lang/String;)Z", 
     (void*)Java_com_xiaomi_media_MyAlgorithmFilter_nativeSetParameter},
};

// JNI 加载函数
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }

    // 注册 native 方法
    jclass clazz = env->FindClass(kClassPathName);
    if (clazz == nullptr) {
        return JNI_ERR;
    }

    if (env->RegisterNatives(clazz, sMethods, sizeof(sMethods) / sizeof(sMethods[0])) < 0) {
        return JNI_ERR;
    }

    return JNI_VERSION_1_6;
}

// JNI 卸载函数
void JNI_OnUnload(JavaVM *vm, void *reserved) {
    if (g_processor) {
        g_processor->release();
        g_processor.reset();
    }
}

// 实现 JNI 方法
JNIEXPORT jboolean JNICALL
Java_com_xiaomi_media_MyAlgorithmFilter_nativeInit(
    JNIEnv *env,
    jobject thiz,
    jint width,
    jint height,
    jfloat strength) {
    
    LOG(INFO) << "Initializing algorithm filter: " 
              << width << "x" << height 
              << ", strength: " << strength;
    
    // 创建算法处理器
    g_processor = myalgorithm::createProcessor();
    if (!g_processor) {
        LOG(ERROR) << "Failed to create algorithm processor";
        return JNI_FALSE;
    }
    
    // 配置参数
    myalgorithm::AlgorithmConfig config;
    config.width = width;
    config.height = height;
    config.format = 0;  // 默认格式
    config.strength = strength;
    config.enable_gpu = true;  // 尝试使用 GPU
    
    // 初始化处理器
    myalgorithm::AlgorithmResult result = g_processor->init(config);
    if (result != myalgorithm::SUCCESS) {
        LOG(ERROR) << "Failed to initialize algorithm processor: " << result;
        g_processor.reset();
        return JNI_FALSE;
    }
    
    LOG(INFO) << "Algorithm filter initialized successfully";
    return JNI_TRUE;
}

JNIEXPORT jboolean JNICALL
Java_com_xiaomi_media_MyAlgorithmFilter_nativeProcess(
    JNIEnv *env,
    jobject thiz,
    jobject inputBuffer,
    jobject outputBuffer,
    jint stride) {
    
    if (!g_processor) {
        LOG(ERROR) << "Algorithm processor not initialized";
        return JNI_FALSE;
    }
    
    // 获取 direct buffer 地址
    uint8_t* input_data = static_cast<uint8_t*>(
        env->GetDirectBufferAddress(inputBuffer));
    uint8_t* output_data = static_cast<uint8_t*>(
        env->GetDirectBufferAddress(outputBuffer));
    
    if (!input_data || !output_data) {
        LOG(ERROR) << "Invalid buffer addresses";
        return JNI_FALSE;
    }
    
    // 执行处理
    myalgorithm::AlgorithmResult result = g_processor->process(
        input_data, output_data, stride);
    
    if (result != myalgorithm::SUCCESS) {
        LOG(ERROR) << "Algorithm processing failed: " << result;
        return JNI_FALSE;
    }
    
    return JNI_TRUE;
}

JNIEXPORT void JNICALL
Java_com_xiaomi_media_MyAlgorithmFilter_nativeRelease(
    JNIEnv *env,
    jobject thiz) {
    
    LOG(INFO) << "Releasing algorithm filter";
    
    if (g_processor) {
        g_processor->release();
        g_processor.reset();
    }
}

JNIEXPORT jint JNICALL
Java_com_xiaomi_media_MyAlgorithmFilter_nativeGetLatency(
    JNIEnv *env,
    jobject thiz) {
    
    if (!g_processor) {
        return -1;
    }
    
    return g_processor->getLatency();
}

JNIEXPORT jboolean JNICALL
Java_com_xiaomi_media_MyAlgorithmFilter_nativeSetParameter(
    JNIEnv *env,
    jobject thiz,
    jstring key,
    jstring value) {
    
    if (!g_processor) {
        return JNI_FALSE;
    }
    
    // 转换 Java 字符串
    const char* key_str = env->GetStringUTFChars(key, nullptr);
    const char* value_str = env->GetStringUTFChars(value, nullptr);
    
    if (!key_str || !value_str) {
        if (key_str) env->ReleaseStringUTFChars(key, key_str);
        if (value_str) env->ReleaseStringUTFChars(value, value_str);
        return JNI_FALSE;
    }
    
    // 处理参数设置
    bool success = true;
    std::string key_cpp(key_str);
    std::string value_cpp(value_str);
    
    if (key_cpp == "strength") {
        // 设置强度参数
        try {
            float strength = std::stof(value_cpp);
            // 这里需要实现参数更新逻辑
            LOG(INFO) << "Set strength to: " << strength;
        } catch (...) {
            success = false;
        }
    } else if (key_cpp == "enable_gpu") {
        // 设置 GPU 启用状态
        bool enable_gpu = (value_cpp == "true");
        LOG(INFO) << "Set GPU enable: " << enable_gpu;
    } else {
        LOG(WARNING) << "Unknown parameter: " << key_cpp;
        success = false;
    }
    
    env->ReleaseStringUTFChars(key, key_str);
    env->ReleaseStringUTFChars(value, value_str);
    
    return success ? JNI_TRUE : JNI_FALSE;
}

Java 层封装

java 复制代码
// com/xiaomi/media/MyAlgorithmFilter.java
package com.xiaomi.media;

import java.nio.ByteBuffer;

public class MyAlgorithmFilter {
    private static final String TAG = "MyAlgorithmFilter";
    
    static {
        System.loadLibrary("myalgorithmfilter_jni");
    }
    
    private boolean mInitialized = false;
    private int mWidth;
    private int mHeight;
    
    /**
     * 初始化算法 filter
     * @param width 图像宽度
     * @param height 图像高度
     * @param strength 处理强度 (0.0 - 2.0)
     * @return 是否初始化成功
     */
    public boolean init(int width, int height, float strength) {
        if (mInitialized) {
            release();
        }
        
        mWidth = width;
        mHeight = height;
        
        mInitialized = nativeInit(width, height, strength);
        return mInitialized;
    }
    
    /**
     * 处理图像 buffer
     * @param inputBuffer 输入 buffer (Direct ByteBuffer)
     * @param outputBuffer 输出 buffer (Direct ByteBuffer)
     * @param stride 图像步长
     * @return 是否处理成功
     */
    public boolean process(ByteBuffer inputBuffer, ByteBuffer outputBuffer, int stride) {
        if (!mInitialized) {
            throw new IllegalStateException("Filter not initialized");
        }
        
        if (!inputBuffer.isDirect() || !outputBuffer.isDirect()) {
            throw new IllegalArgumentException("Buffers must be direct buffers");
        }
        
        return nativeProcess(inputBuffer, outputBuffer, stride);
    }
    
    /**
     * 释放资源
     */
    public void release() {
        if (mInitialized) {
            nativeRelease();
            mInitialized = false;
        }
    }
    
    /**
     * 获取处理延迟 (微秒)
     * @return 处理延迟
     */
    public int getLatency() {
        if (!mInitialized) {
            return -1;
        }
        return nativeGetLatency();
    }
    
    /**
     * 设置参数
     * @param key 参数名
     * @param value 参数值
     * @return 是否设置成功
     */
    public boolean setParameter(String key, String value) {
        if (!mInitialized) {
            return false;
        }
        return nativeSetParameter(key, value);
    }
    
    /**
     * 设置处理强度
     * @param strength 强度值 (0.0 - 2.0)
     * @return 是否设置成功
     */
    public boolean setStrength(float strength) {
        return setParameter("strength", String.valueOf(strength));
    }
    
    /**
     * 设置是否启用 GPU
     * @param enable 是否启用
     * @return 是否设置成功
     */
    public boolean setGPUEnabled(boolean enable) {
        return setParameter("enable_gpu", String.valueOf(enable));
    }
    
    @Override
    protected void finalize() throws Throwable {
        try {
            release();
        } finally {
            super.finalize();
        }
    }
    
    // Native 方法声明
    private native boolean nativeInit(int width, int height, float strength);
    private native boolean nativeProcess(ByteBuffer inputBuffer, ByteBuffer outputBuffer, int stride);
    private native void nativeRelease();
    private native int nativeGetLatency();
    private native boolean nativeSetParameter(String key, String value);
}

使用示例

java 复制代码
// 使用示例
public class MyActivity extends Activity {
    private MyAlgorithmFilter mFilter;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 初始化 filter
        mFilter = new MyAlgorithmFilter();
        boolean success = mFilter.init(1920, 1080, 1.5f);
        
        if (success) {
            // 设置参数
            mFilter.setGPUEnabled(true);
            
            // 创建 direct buffers
            ByteBuffer inputBuffer = ByteBuffer.allocateDirect(1920 * 1080 * 3 / 2);
            ByteBuffer outputBuffer = ByteBuffer.allocateDirect(1920 * 1080 * 3 / 2);
            
            // 处理图像
            boolean processed = mFilter.process(inputBuffer, outputBuffer, 1920);
            
            if (processed) {
                // 获取处理延迟
                int latency = mFilter.getLatency();
                Log.d(TAG, "Processing latency: " + latency + " microseconds");
            }
        }
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mFilter != null) {
            mFilter.release();
        }
    }
}

完整示例

编译配置

blueprint 复制代码
// Android.bp
cc_library_shared {
    name: "libmyalgorithmfilter",
    vendor: true,
    shared_libs: [
        "libcodec2",
        "libcodec2_components",
        "liblog",
        "libutils",
        "libbase",
        "libEGL",
        "libGLESv2",
    ],
    static_libs: [
        "libarect",
    ],
    srcs: [
        "MyAlgorithmC2Component.cpp",
        "MyAlgorithmFilterPlugin.cpp",
        "MyAlgorithmProcessor.cpp",
    ],
    cflags: [
        "-Wall",
        "-Werror",
        "-Wno-unused-parameter",
        "-DUSE_GPU=1",
    ],
    include_dirs: [
        "frameworks/av/media/codec2/components/include",
        "frameworks/av/media/codec2/core/include",
        "frameworks/av/media/codec2/vndk/include",
    ],
}

cc_library_shared {
    name: "libmyalgorithmfilter_jni",
    vendor: true,
    shared_libs: [
        "libmyalgorithmfilter",
        "liblog",
        "libutils",
        "libnativehelper",
    ],
    srcs: [
        "jni/MyAlgorithmFilter_jni.cpp",
    ],
    cflags: [
        "-Wall",
        "-Werror",
    ],
}

部署脚本

bash 复制代码
#!/bin/bash
# deploy_filter.sh

# 编译
echo "Building algorithm filter..."
mmm vendor/xiaomi/proprietary/multimedia/algorithm-filter/

if [ $? -ne 0 ]; then
    echo "Build failed!"
    exit 1
fi

# 推送到设备
echo "Deploying to device..."
adb push out/target/product/$TARGET_PRODUCT/vendor/lib64/libmyalgorithmfilter.so /vendor/lib64/
adb push out/target/product/$TARGET_PRODUCT/vendor/lib64/libmyalgorithmfilter_jni.so /vendor/lib64/

# 创建符号链接
echo "Creating symbolic link..."
adb shell "ln -sf /vendor/lib64/libmyalgorithmfilter.so /vendor/lib64/libc2filterplugin.so"

# 设置权限
echo "Setting permissions..."
adb shell "chmod 644 /vendor/lib64/libmyalgorithmfilter.so"
adb shell "chmod 644 /vendor/lib64/libmyalgorithmfilter_jni.so"

# 启用 filter
echo "Enabling filter..."
adb shell "setprop vendor.my.algorithm.filter.enable true"

echo "Deployment completed!"

调试与优化

调试技巧

  1. 日志标签定义
cpp 复制代码
#define LOG_TAG "MyAlgorithmFilter"
#define LOG_NDEBUG 0
#include <utils/Log.h>
  1. 性能监控
cpp 复制代码
class PerformanceMonitor {
public:
    void start() {
        start_time_ = std::chrono::high_resolution_clock::now();
    }
    
    void end(const std::string& operation) {
        auto end_time = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
            end_time - start_time_);
        ALOGD("%s took %lld microseconds", operation.c_str(), duration.count());
    }
    
private:
    std::chrono::high_resolution_clock::time_point start_time_;
};
  1. 内存监控
cpp 复制代码
void logMemoryUsage() {
    std::ifstream status("/proc/self/status");
    std::string line;
    while (std::getline(status, line)) {
        if (line.find("VmSize") != std::string::npos ||
            line.find("VmRSS") != std::string::npos) {
            ALOGD("%s", line.c_str());
        }
    }
}

性能优化

  1. GPU 优化

    • 使用纹理缓存
    • 批量处理多帧
    • 优化着色器代码
  2. CPU 优化

    • 使用 SIMD 指令
    • 多线程并行处理
    • 内存对齐
  3. 内存优化

    • 使用内存池
    • 避免频繁分配释放
    • 使用零拷贝技术

JAVA侧 CODEC 调用(user)

java 复制代码
        // Java 应用层代码
        MediaCodec codec = null;
        try {
            // 关键点:直接使用你在 HAL 层注册的名字
            codec = MediaCodec.createByCodecName("c2.myvendor.custom.avc.decoder");

            // 后续 configure, start, queueInputBuffer, dequeueOutputBuffer 完全标准流程
//            MediaFormat format;
//            codec.configure(format, surface, null, 0);
//            codec.start();

            // ... 正常使用
        } catch (IOException e) {
            Log.e("MyCodec", "Failed to create custom codec", e);
        }

常见问题

1. Filter 未生效

问题: Filter 编译部署后没有生效

解决方案:

bash 复制代码
# 检查符号链接
adb shell "ls -la /vendor/lib64/libc2filterplugin.so"

# 检查系统属性
adb shell "getprop vendor.my.algorithm.filter.enable"

# 检查日志
adb logcat -s MyAlgorithmFilter:* Codec2-FilterWrapper:*

2. 内存泄漏

问题: 长时间运行后内存持续增长

解决方案:

  • 使用智能指针管理资源
  • 实现正确的析构函数
  • 使用内存检测工具

3. 性能问题

问题: 处理延迟过高

解决方案:

  • 启用 GPU 加速
  • 优化算法复杂度
  • 使用性能分析工具

4. 兼容性问题

问题: 在某些设备上无法运行

解决方案:

  • 检查硬件支持
  • 提供降级方案
  • 测试不同平台

总结

通过本文档的详细介绍,你应该能够:

  1. 理解 Android Codec2 Filter 的架构和工作原理
  2. 封装自己的算法模块为 Codec2 组件
  3. 实现 Filter Plugin 并集成到系统中
  4. 通过 JNI 接口在 Java 层调用算法功能
  5. 进行调试和性能优化

关键要点:

  • 正确实现 C2Component 接口
  • 合理管理 buffer 和内存
  • 处理好线程同步
  • 提供完善的错误处理
  • 进行充分的测试和优化

希望这份指南能帮助你成功开发自己的算法 filter 模块!

相关推荐
lichenyang4535 小时前
媒体选择、上传与音频采集 API 实现流程
oracle·音视频·媒体·android-studio
IT大白鼠5 小时前
AIGC性能的关键瓶颈:算力、数据、算法三者如何互相制约?
算法·aigc
赏金术士5 小时前
Kotlin 数据流与单双向绑定
android·开发语言·kotlin
白雪茫茫5 小时前
监督学习、半监督学习、无监督学习算法详解
python·学习·算法·ai
FengyunSky6 小时前
浅析 空间频率响应 SFR 计算
算法
树下水月6 小时前
PHP 一种改良版的雪花算法
算法·php·dreamweaver
小白学鸿蒙6 小时前
Unity 3D 2023解压安装,配置安卓运行环境后打包安卓应用(踩坑无数之差点放弃)
android·unity·游戏引擎
一只数据集6 小时前
全尺寸人形机器人灵巧手力觉触觉数据集-2908条ROSbag数据覆盖14大应用场景深度解析
大数据·人工智能·算法·机器人
阿巴斯甜7 小时前
2026小知识点(9)
android
罗西的思考8 小时前
【GUI-Agent】阿里通义MAI-UI 代码阅读(2)--- 实现
人工智能·算法·机器学习