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 模块!

相关推荐
无忧智库2 小时前
低空经济新基建:构建低空飞行大数据中心与行业应用算法工厂的全景式蓝图(WORD)
算法
闻缺陷则喜何志丹3 小时前
【背包 组合】P7552 [COCI 2020/2021 #6] Anagramistica|普及+
c++·算法·背包·洛谷·组合
y = xⁿ3 小时前
MySQL:count(1)与count(*)有什么区别,深分页问题
android·数据库·mysql
小章UPUP4 小时前
2026年第十六届MathorCup数学应用挑战赛D题国奖思路
算法
hssfscv4 小时前
软件设计师下午试题四——C语言(N皇后问题、分治、动态规划)
c语言·算法·动态规划
lolo大魔王4 小时前
Go语言的反射机制
开发语言·后端·算法·golang
白羊by4 小时前
Softmax 激活函数详解:从数学原理到应用场景
网络·人工智能·深度学习·算法·损失函数
故事和你914 小时前
洛谷-算法1-7-搜索3
数据结构·c++·算法·leetcode·动态规划
EasyDSS4 小时前
私有化视频会议系统/企业级融媒体生产管理平台EasyDSS一体化视频平台赋能各行业数字化
音视频·媒体