android AV 之 SimpleC2Component

一、总体架构

以 aac 解码 process 为例
App (MediaCodec) -> Framework (CCodec) -> Binder (HIDL/AIDL) -> mediaswcodec 进程 -> SimpleC2Component (基类循环) -> C2SoftAacDec::process

Android 调用到 libcodec2_soft_aacdec.so 里的 process 的关键步骤是:

  1. 加载库 :系统启动 mediaswcodec 服务进程,根据配置加载 libcodec2_soft_aacdec.so 并创建 C2SoftAacDec 对象。
  2. 基类驱动 :该对象启动时会创建一个后台线程(由基类 SimpleC2Component 管理)。
  3. 循环处理 :后台线程运行 processQueue() 循环,等待输入数据。
  4. 虚函数调用 :一旦收到数据,基类直接调用 process() 虚函数。
  5. 具体执行 :执行流进入 C2SoftAacDec::process,完成 AAC 解码。

二、函数分析

1. SimpleC2Component::processQueue

1.1 函数功能
  1. 队列管理:从工作队列中取出任务,处理flush和排空操作
  2. 资源初始化:首次使用时初始化输出块池
  3. 配置更新:处理工作项中的配置参数更新
  4. 任务处理:调用具体的process函数处理音视频数据
  5. 结果返回:根据处理状态立即返回结果或将工作放入挂起队列
  6. 错误处理:处理各种异常情况并通知监听器
1.2 函数注释
cpp 复制代码
bool SimpleC2Component::processQueue() {
    // 声明变量:工作项、代际、排空模式等
    std::unique_ptr<C2Work> work;
    uint64_t generation;
    int32_t drainMode;
    bool isFlushPending = false;
    bool hasQueuedWork = false;
    
    {
        // 获取工作队列的锁
        Mutexed<WorkQueue>::Locked queue(mWorkQueue);
        // 检查队列是否为空
        if (queue->empty()) {
            return false;  // 队列为空,返回false表示没有工作需要处理
        }

        // 获取当前队列的代际信息(用于检测flush操作)
        generation = queue->generation();
        // 获取排空模式
        drainMode = queue->drainMode();
        // 检查是否有待处理的flush操作
        isFlushPending = queue->popPendingFlush();
        // 从队列前端取出一个工作项
        work = queue->pop_front();
        // 检查队列是否还有剩余工作
        hasQueuedWork = !queue->empty();
    }
    
    // 如果有待处理的flush操作,执行flush
    if (isFlushPending) {
        ALOGV("processing pending flush");
        // 调用flush处理函数
        c2_status_t err = onFlush_sm();
        if (err != C2_OK) {
            ALOGD("flush err: %d", err);
            // TODO: 错误处理
        }
    }

    // 如果输出块池尚未初始化,进行初始化
    if (!mOutputBlockPool) {
        c2_status_t err = [this] {
            // 查询输出格式配置
            C2StreamBufferTypeSetting::output outputFormat(0u);
            std::vector<std::unique_ptr<C2Param>> params;
            // 查询块池调优参数
            c2_status_t err = intf()->query_vb(
                    { &outputFormat },
                    { C2PortBlockPoolsTuning::output::PARAM_TYPE },
                    C2_DONT_BLOCK,
                    &params);
            if (err != C2_OK && err != C2_BAD_INDEX) {
                ALOGD("query err = %d", err);
                return err;
            }
            // 根据输出格式确定块池ID
            C2BlockPool::local_id_t poolId =
                outputFormat.value == C2BufferData::GRAPHIC
                        ? C2BlockPool::BASIC_GRAPHIC
                        : C2BlockPool::BASIC_LINEAR;
            // 如果有参数返回,使用配置的块池
            if (params.size()) {
                C2PortBlockPoolsTuning::output *outputPools =
                    C2PortBlockPoolsTuning::output::From(params[0].get());
                if (outputPools && outputPools->flexCount() >= 1) {
                    poolId = outputPools->m.values[0];
                }
            }

            // 获取块池实例
            std::shared_ptr<C2BlockPool> blockPool;
            err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool);
            ALOGD("Using output block pool with poolID %llu => got %llu - %d",
                    (unsigned long long)poolId,
                    (unsigned long long)(
                            blockPool ? blockPool->getLocalId() : 111000111),
                    err);
            if (err == C2_OK) {
                // 创建阻塞式块池包装器
                mOutputBlockPool = std::make_shared<BlockingBlockPool>(blockPool);
            }
            return err;
        }();
        // 如果块池初始化失败,发送错误通知
        if (err != C2_OK) {
            Mutexed<ExecState>::Locked state(mExecState);
            std::shared_ptr<C2Component::Listener> listener = state->mListener;
            state.unlock();
            listener->onError_nb(shared_from_this(), err);
            return hasQueuedWork;
        }
    }

    // 如果work为空,表示是排空操作
    if (!work) {
        // 执行排空处理
        c2_status_t err = drain(drainMode, mOutputBlockPool);
        if (err != C2_OK) {
            // 排空失败,发送错误通知
            Mutexed<ExecState>::Locked state(mExecState);
            std::shared_ptr<C2Component::Listener> listener = state->mListener;
            state.unlock();
            listener->onError_nb(shared_from_this(), err);
        }
        return hasQueuedWork;
    }

    {
        // 处理配置更新
        std::vector<C2Param *> updates;
        // 收集所有配置更新参数
        for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
            if (param) {
                updates.emplace_back(param.get());
            }
        }
        // 应用配置更新
        if (!updates.empty()) {
            std::vector<std::unique_ptr<C2SettingResult>> failures;
            c2_status_t err = intf()->config_vb(updates, C2_MAY_BLOCK, &failures);
            ALOGD("applied %zu configUpdates => %s (%d)", updates.size(), asString(err), err);
        }
    }

    // 记录处理开始
    ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
    
    // 处理空输入缓冲区的情况
    if (!work->input.buffers.empty() && !work->input.buffers[0]) {
        ALOGD("Encountered null input buffer. Clearing the input buffer");
        work->input.buffers.clear();
    }
    
    // 核心处理:调用具体的处理函数
    process(work, mOutputBlockPool);
    ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
    
    {
        // 再次获取队列锁,检查代际是否变化
        Mutexed<WorkQueue>::Locked queue(mWorkQueue);
        if (queue->generation() != generation) {
            ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
                    queue->generation(), generation);
            // 代际已变化,标记工作为未找到
            work->result = C2_NOT_FOUND;
            queue.unlock();

            // 通知监听器工作完成
            Mutexed<ExecState>::Locked state(mExecState);
            std::shared_ptr<C2Component::Listener> listener = state->mListener;
            state.unlock();
            listener->onWorkDone_nb(shared_from_this(), vec(work));
            return hasQueuedWork;
        }
        
        // 检查工作是否已处理完成
        if (work->workletsProcessed != 0u) {
            queue.unlock();
            // 工作已处理完成,立即返回结果
            Mutexed<ExecState>::Locked state(mExecState);
            ALOGV("returning this work");
            std::shared_ptr<C2Component::Listener> listener = state->mListener;
            state.unlock();
            listener->onWorkDone_nb(shared_from_this(), vec(work));
        } else {
            // 工作尚未处理完成,放入挂起队列
            ALOGV("queue pending work");
            work->input.buffers.clear();
            std::unique_ptr<C2Work> unexpected;

            // 获取帧索引
            uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
            // 检查是否已有相同帧索引的挂起工作
            if (queue->pending().count(frameIndex) != 0) {
                unexpected = std::move(queue->pending().at(frameIndex));
                queue->pending().erase(frameIndex);
            }
            // 将当前工作放入挂起队列
            (void)queue->pending().insert({ frameIndex, std::move(work) });

            queue.unlock();
            // 如果有意外的工作项,发送错误通知
            if (unexpected) {
                ALOGD("unexpected pending work");
                unexpected->result = C2_CORRUPTED;
                Mutexed<ExecState>::Locked state(mExecState);
                std::shared_ptr<C2Component::Listener> listener = state->mListener;
                state.unlock();
                listener->onWorkDone_nb(shared_from_this(), vec(unexpected));
            }
        }
    }
    // 返回是否还有待处理的工作
    return hasQueuedWork;
}
相关推荐
TAEHENGV2 小时前
导入导出模块 Cordova 与 OpenHarmony 混合开发实战
android·javascript·数据库
君莫啸ོ3 小时前
Android基础-SwitchCompat自定义样式
android
5980354153 小时前
【java工具类】小数、整数转中文小写
android·java·开发语言
csj503 小时前
安卓基础之《(8)—中级控件(2)选择按钮》
android
液态不合群3 小时前
【面试题】MySQL 中的索引数量是否越多越好?为什么?
android·数据库·mysql
QING6184 小时前
Kotlin协程:Job.cancel() 和 Scope.cancel() 的区别详解!!!
android·kotlin·android jetpack
Zender Han4 小时前
Flutter 图片裁剪插件 image_cropper 最新版介绍与使用教程
android·flutter·ios
方白羽4 小时前
Android 与 iOS 动态更换应用图标实现方案
android·ios·app
nono牛4 小时前
MTK平台Android init.rc服务详解实例
android·gitee