【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 4】【05】

承接上一章节分析:【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 4】【04】
本系列文章分析的安卓源码版本:【Android 10.0 版本】

【此章节小节编号就接着上一章节排列】
8.3.2.2、BufferInfo结构定义:
缓冲区buffer信息结构定义,该结构非常重要,它将是编解码器工作时传递数据的载体。
ACodec内部定义

// [frameworks/av/media/libstagefright/include/media/stagefright/ACodec.h]
    struct BufferInfo {
    	// 当前buffer对象的状态拥有者
        enum Status {
        	// ACodec自身
            OWNED_BY_US,
            // 底层组件(编解码器)端
            OWNED_BY_COMPONENT,
            // 推流端
            OWNED_BY_UPSTREAM,
            // 拉流端
            OWNED_BY_DOWNSTREAM,
            // Surface端
            OWNED_BY_NATIVE_WINDOW,
            UNRECOGNIZED,            // not a tracked buffer
        };

        // 一个快速安全判断当前buffer状态的内联方法
        static inline Status getSafeStatus(BufferInfo *info) {
            return info == NULL ? UNRECOGNIZED : info->mStatus;
        }
		
		// buffer id,非常重要的标志了缓冲区中每一个buffer的唯一性
		// typedef uint32_t buffer_id;
        IOMX::buffer_id mBufferID;
        // buffer状态
        Status mStatus;
        // buffer出队列计数值,它是个随着buffer产生不断递增的计数值
        unsigned mDequeuedAt;

        // 编解码器buffer数据对象
        // 备注:其实际只是个代理ABuffer类的代理类实现,
        // 关于ABuffer类的源码实现分析请见早前相关章节分析,因此不再分析。
        // 注意:此处的英文注释对我们也有理解上的帮助,
        // 也就是该buffer是客户端(ACodec)管理使用的buffer数据类型,
        // 如果没有使用数据转换器(此前分析过它),那么该Buffer将会是编解码器的buffer数据类型,
        // 否则该buffer将会被分开(另外)分配内存并指向一个IMemory数据类型的引用。
        sp<MediaCodecBuffer> mData;  // the client's buffer; if not using data conversion, this is
                                     // the codec buffer; otherwise, it is allocated separately
        // 这就是需要数据转换器时的指针,指向一个IMemory数据类型的引用
        sp<RefBase> mMemRef;         // and a reference to the IMemory, so it does not go away
        // 需要数据转换器时,此对象将会编解码器的buffer,也就是和上面的mData分开分配内存
        sp<MediaCodecBuffer> mCodecData;  // the codec's buffer
        // 需要数据转换器时,指向IMemory数据类型的引用
        sp<RefBase> mCodecRef;            // and a reference to the IMemory
		// 总结下上面这四个参数的关系:
		// 也就是一个Data buffer对象必须对应一个指向IMemory数据类型对象的引用,
		// 然后就是若需要数据转换器时上面四个参数将都会使用,否则直接使用前两个参数对象即可(不需要分开分配内存)

        // 图形Buffer信息对象
        // 其简单声明见下面
        sp<GraphicBuffer> mGraphicBuffer;
        // 是否为新图形数据buffer
        bool mNewGraphicBuffer;
        // 当前buffer的Fence文件描述符
        // 注意:该值其实非常重要,Fence是系统管理某些Buffer分配和释放(即buffer读写同步机制)的同步机制,
        // 由同步点和同步时间线来管理同步
        // 后续分析到看详细分析
        int mFenceFd;
        // 帧渲染跟踪器的记录已渲染帧数据对象
        // 其声明定义见下面
        FrameRenderTracker::Info *mRenderInfo;

        // 根据注释可知,这下面的五个声明只用于debug,因此不分析
        // The following field and 4 methods are used for debugging only
        // 标记是否为读状态的Fence
        bool mIsReadFence;
        // Store |fenceFd| and set read/write flag. Log error, if there is already a fence stored.
        void setReadFence(int fenceFd, const char *dbg);
        void setWriteFence(int fenceFd, const char *dbg);
        // Log error, if the current fence is not a read/write fence.
        void checkReadFence(const char *dbg);
        void checkWriteFence(const char *dbg);
    };

GraphicBuffer类声明:
图形Buffer信息类声明
类声明:省略其它代码

// [frameworks/native/libs/ui/include/ui/GraphicBuffer.h]
class GraphicBuffer
    : public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,
      public Flattenable<GraphicBuffer> {}

// [frameworks/native/libs/ui/include/ui/ANativeObjectBase.h]
// 可以看到该父类仅仅只是为了实现一个代理接口,最终还是继承了【NATIVE_TYPE】和【REF】类
/*
 * This helper class turns a ANativeXXX object type into a C++
 * reference-counted object; with proper type conversions.
 */
template <typename NATIVE_TYPE, typename TYPE, typename REF,
        typename NATIVE_BASE = android_native_base_t>
class ANativeObjectBase : public NATIVE_TYPE, public REF {}

// [system/core/libutils/include/utils/Flattenable.h]
// 实现可扁平化数据,处理数据字节的序列化
/*
 * The Flattenable protocol allows an object to serialize itself out
 * to a byte-buffer and an array of file descriptors.
 * Flattenable objects must implement this protocol.
 */
template <typename T>
class Flattenable {
public:
    // size in bytes of the flattened object
    inline size_t getFlattenedSize() const;

    // number of file descriptors to flatten
    inline size_t getFdCount() const;

    // flattens the object into buffer.
    // size should be at least of getFlattenedSize()
    // file descriptors are written in the fds[] array but ownership is
    // not transfered (ie: they must be dupped by the caller of
    // flatten() if needed).
    inline status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;

    // unflattens the object from buffer.
    // size should be equal to the value of getFlattenedSize() when the
    // object was flattened.
    // unflattened file descriptors are found in the fds[] array and
    // don't need to be dupped(). ie: the caller of unflatten doesn't
    // keep ownership. If a fd is not retained by unflatten() it must be
    // explicitly closed.
    inline status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
};

FrameRenderTracker::Info类声明:
帧渲染跟踪器的记录已渲染帧数据对象。
根据英文注释基本可以理解该信息类的作用:
追踪渲染器一帧数据信息,主要追踪帧数据的三个状态

// Tracks the render information about a frame. Frames go through several states while
// the render information is tracked:
//
// 1. queued frame: mMediaTime and mGraphicBuffer are set for the frame. mFence is the
// queue fence (read fence). mIndex is negative, and mRenderTimeNs is invalid.
// Key characteristics: mFence is not NULL and mIndex is negative.
//
// 2. dequeued frame: mFence is updated with the dequeue fence (write fence). mIndex is set.
// Key characteristics: mFence is not NULL and mIndex is non-negative. mRenderTime is still
// invalid.
//
// 3. rendered frame or frame: mFence is cleared, mRenderTimeNs is set.
// Key characteristics: mFence is NULL.
//
struct RenderedFrameInfo {
    // set by client during onFrameQueued or onFrameRendered
    int64_t getMediaTimeUs() const  { return mMediaTimeUs; }

    // -1 if frame is not yet rendered
    nsecs_t getRenderTimeNs() const { return mRenderTimeNs; }

    // set by client during updateRenderInfoForDequeuedBuffer; -1 otherwise
    ssize_t getIndex() const        { return mIndex; }

    // creates information for a queued frame
    RenderedFrameInfo(int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer,
            const sp<Fence> &fence)
        : mMediaTimeUs(mediaTimeUs),
          mRenderTimeNs(-1),
          mIndex(-1),
          mGraphicBuffer(graphicBuffer),
          mFence(fence) {
    }

    // creates information for a frame rendered on a tunneled surface
    RenderedFrameInfo(int64_t mediaTimeUs, nsecs_t renderTimeNs)
        : mMediaTimeUs(mediaTimeUs),
          mRenderTimeNs(renderTimeNs),
          mIndex(-1),
          mGraphicBuffer(NULL),
          mFence(NULL) {
    }

private:
	// 当前帧媒体时间戳
    int64_t mMediaTimeUs;
    // 当前帧渲染时间戳
    nsecs_t mRenderTimeNs;
    // 帧索引
    ssize_t mIndex;         // to be used by client
    // 帧图形数据buffer的指针对象
    sp<GraphicBuffer> mGraphicBuffer;
    // Fence同步机制的指针对象
    sp<Fence> mFence;

    // 帧渲染跟踪器,它将跟踪记录当前已渲染帧数据
    friend struct FrameRenderTracker;
};

8.3.2.3、客户端使用的buffer缓存数据为VideoNativeMetadata数据类型结构声明定义:
视频native元数据结构

// [frameworks/native/headers/media_plugin/media/hardware/HardwareAPI.h]
struct VideoNativeMetadata {
	// 元数据buffer类型枚举,此处必须为kMetadataBufferTypeANWBuffer
	// 关于它前面章节已有分析过
    MetadataBufferType eType;               // must be kMetadataBufferTypeANWBuffer
#ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    OMX_PTR pBuffer;
#else
	// 64位平台默认使用该数据Buffer类型
    struct ANativeWindowBuffer* pBuffer;
#endif
    int nFenceFd;                           // -1 if unused
};

// 元数据缓冲区布局,用于将native_handle传递给编解码器
// Meta data buffer layout for passing a native_handle to codec
struct VideoNativeHandleMetadata {
    MetadataBufferType eType;               // must be kMetadataBufferTypeNativeHandleSource

#ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
    OMX_PTR pHandle;
#else
	// buffer元数据native访问句柄指针
	// 见下面定义
    native_handle_t *pHandle;
#endif
};

native_handle_t 声明定义:
buffer元数据native访问句柄指针

// [system/core/libcutils/include/cutils/native_handle.h]
typedef struct native_handle
{
    int version;        /* sizeof(native_handle_t) */
    int numFds;         /* number of file-descriptors at &data[0] */
    int numInts;        /* number of ints at &data[numFds] */
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wzero-length-array"
#endif
    int data[0];        /* numFds + numInts ints */
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
} native_handle_t;

8.3.2.4、mOMXNode->useBuffer(kPortIndexOutput, OMXBuffer::sPreset, &info.mBufferID)实现分析:
请求底层组件输出端口使用该Buffer
现来看OMXBuffer::sPreset定义:可以看到OMXBuffer只是用于进行HIDL数据传递转换的一个类型,完成之后将会被转换为CodecBuffer类型
省略部分代码

// [frameworks/av/media/libmedia/include/media/OMXBuffer.h]

// TODO: After complete HIDL transition, this class would be replaced by
// CodecBuffer.
class OMXBuffer {
public:
	// 类静态变量,预设的OMX Buffer
    // sPreset is used in places where we are referring to a pre-registered
    // buffer on a port. It has type kBufferTypePreset and mRangeLength of 0.
    static OMXBuffer sPreset;

private:
    friend struct OMXNodeInstance;
    friend struct C2OMXNode;

    // This is needed temporarily for OMX HIDL transition.
    friend inline bool (::android::hardware::media::omx::V1_0::implementation::
            wrapAs)(::android::hardware::media::omx::V1_0::CodecBuffer* t,
            OMXBuffer const& l);
    friend inline bool (::android::hardware::media::omx::V1_0::implementation::
            convertTo)(OMXBuffer* l,
            ::android::hardware::media::omx::V1_0::CodecBuffer const& t);
    friend inline bool (::android::hardware::media::omx::V1_0::utils::
            wrapAs)(::android::hardware::media::omx::V1_0::CodecBuffer* t,
            OMXBuffer const& l);
    friend inline bool (::android::hardware::media::omx::V1_0::utils::
            convertTo)(OMXBuffer* l,
            ::android::hardware::media::omx::V1_0::CodecBuffer const& t);

    enum BufferType {
        kBufferTypeInvalid = 0,
        kBufferTypePreset,
        kBufferTypeSharedMem,
        kBufferTypeANWBuffer, // Use only for non-Treble
        kBufferTypeNativeHandle,
        kBufferTypeHidlMemory // Mapped to CodecBuffer::Type::SHARED_MEM.
    };

    BufferType mBufferType;

    // kBufferTypePreset
    // If the port is operating in byte buffer mode, mRangeLength is the valid
    // range length. Otherwise the range info should also be ignored.
    OMX_U32 mRangeOffset;
    OMX_U32 mRangeLength;

    // kBufferTypeSharedMem
    sp<IMemory> mMem;

    // kBufferTypeANWBuffer
    sp<GraphicBuffer> mGraphicBuffer;

    // kBufferTypeNativeHandle
    sp<NativeHandle> mNativeHandle;

    // kBufferTypeHidlMemory
    hidl_memory mHidlMemory;    
}

sPreset变量的初始化:

// [frameworks/av/media/libmedia/OMXBuffer.cpp]
//static
OMXBuffer OMXBuffer::sPreset(static_cast<sp<MediaCodecBuffer> >(NULL));

// 默认执行该构造函数
OMXBuffer::OMXBuffer(const sp<MediaCodecBuffer>& codecBuffer)
    : mBufferType(kBufferTypePreset),
      mRangeOffset(codecBuffer != NULL ? codecBuffer->offset() : 0),
      mRangeLength(codecBuffer != NULL ? codecBuffer->size() : 0) {
}

useBuffer实现分析:

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::useBuffer(
        OMX_U32 portIndex, const OMXBuffer &omxBuffer, IOMX::buffer_id *buffer) {
    if (buffer == NULL) {
        ALOGE("b/25884056");
        return BAD_VALUE;
    }

    if (portIndex == kPortIndexInputExtradata || portIndex == kPortIndexOutputExtradata) {
        // Allow extradata ports
    } else if (portIndex >= NELEM(mNumPortBuffers)) {
        return BAD_VALUE;
    }

    Mutex::Autolock autoLock(mLock);
    if (mHandle == NULL) {
        return DEAD_OBJECT;
    }

    // 注意根据前面流程分析,可知mSailed参数此时还是true即表示OMX正在启动状态中
    if (!mSailed) {
        ALOGE("b/35467458");
        android_errorWriteLog(0x534e4554, "35467458");
        return BAD_VALUE;
    }

    // 根据buffer类型判断,默认值为kBufferTypePreset
    switch (omxBuffer.mBufferType) {
    	// 其实该预设Buffer类型默认为字节数据存储的内存buffer,通过下面的useBuffer_1中的分析就会知晓区别了
        case OMXBuffer::kBufferTypePreset: {
            if (mPortMode[portIndex] != IOMX::kPortModeDynamicANWBuffer
                    && mPortMode[portIndex] != IOMX::kPortModeDynamicNativeHandle) {
                // 若不是这两中buffer端口模式类型,则直接结束    
                break;
            }
            // 请求底层组件输出端口使用该Buffer
            // 见8.3.2.4.1小节分析
            return useBuffer_l(portIndex, NULL, NULL, buffer);
        }

        // 此处使用的共享内存Buffer类型,也就是不需要新创建单独内存来存储,直接共享使用【omxBuffer.mMem】
        case OMXBuffer::kBufferTypeSharedMem: {
            if (mPortMode[portIndex] != IOMX::kPortModePresetByteBuffer
                    && mPortMode[portIndex] != IOMX::kPortModeDynamicANWBuffer) {
                break;
            }
            return useBuffer_l(portIndex, omxBuffer.mMem, NULL, buffer);
        }

        // Surface Buffer类型时
        case OMXBuffer::kBufferTypeANWBuffer: {
            if (mPortMode[portIndex] != IOMX::kPortModePresetANWBuffer
                    && mPortMode[portIndex] != IOMX::kPortModeDynamicANWBuffer) {
                // 非这两种端口模式时,退出
                break;
            }
            // 使用图形Buffer
            // 见8.3.2.4.2小节分析
            return useGraphicBuffer_l(portIndex, omxBuffer.mGraphicBuffer, buffer);
        }

        // HIDL通信的Buffer类型时
        case OMXBuffer::kBufferTypeHidlMemory: {
                if (portIndex == kPortIndexInputExtradata || portIndex == kPortIndexOutputExtradata) {
                // Allow extradata ports
                } else if (mPortMode[portIndex] != IOMX::kPortModePresetByteBuffer
                        && mPortMode[portIndex] != IOMX::kPortModeDynamicANWBuffer
                        && mPortMode[portIndex] != IOMX::kPortModeDynamicNativeHandle) {
                    break;
                }
                // 支持上面五种端口Buffer类型
                // 映射数据内存,实际上就是内存映射(Memory Map) 技术,不展开分析
                sp<IHidlMemory> hidlMemory = mapMemory(omxBuffer.mHidlMemory);
                if (hidlMemory == nullptr) {
                	// 映射内存失败
                    ALOGE("OMXNodeInstance useBuffer() failed to map memory");
                    return NO_MEMORY;
                }
                // 将前面分析
                return useBuffer_l(portIndex, NULL, hidlMemory, buffer);
        }
        default:
            return BAD_VALUE;
            break;
    }

    ALOGE("b/77486542 : bufferType = %d vs. portMode = %d",
          omxBuffer.mBufferType, mPortMode[portIndex]);
    android_errorWriteLog(0x534e4554, "77486542");
    return INVALID_OPERATION;
}

8.3.2.4.1、useBuffer_l(portIndex, NULL, NULL, buffer)实现分析:
请求底层组件输出端口使用该Buffer

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::useBuffer_l(
        OMX_U32 portIndex, const sp<IMemory> &params,
        const sp<IHidlMemory> &hParams, IOMX::buffer_id *buffer) {
    // Buffer元数据结构对象指针,其实就是此前大致已阐述过的实现,
    // 它实际控制管理IMemory、IHidlMemory、GraphicBuffer这三种buffer数据类型的实现。
    // 不再详细分析,后续涉及到时会简单提示其实现原理
    BufferMeta *buffer_meta;
    // OMX Buffer头信息类型对象指针,该数据由底层组件创建返回
    OMX_BUFFERHEADERTYPE *header;
    OMX_ERRORTYPE err = OMX_ErrorNone;
    // 判断是否为媒体元数据(也就是音视频输入输出端口buffer数据)
     bool isMetadata;
    if (portIndex == kPortIndexInputExtradata || portIndex == kPortIndexOutputExtradata) {
        isMetadata = false;
    } else {
    	// mMetadataType记录的就是每个buffer端口媒体元数据类型
    	// 该值的赋值是在此前的【OMXNodeInstance::setPortMode】流程中分析到的
        isMetadata = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
    }

    if (portIndex == kPortIndexInputExtradata || portIndex == kPortIndexOutputExtradata) {
        // Allow extradata ports
    } else if (!isMetadata && mGraphicBufferEnabled[portIndex]) {
        ALOGE("b/62948670");
        android_errorWriteLog(0x534e4554, "62948670");
        return INVALID_OPERATION;
    }

    // 参数大小,参数指针
    size_t paramsSize;
    void* paramsPointer;
    // 此处可以看出IMemory、IHidlMemory 这两种buffer数据类型不能同时启用
    if (params != NULL && hParams != NULL) {
        return BAD_VALUE;
    }
    // 获取其对应的参数大小和参数指针(即指向数据起始位置地址)
    if (params != NULL) {
        paramsPointer = params->pointer();
        paramsSize = params->size();
    } else if (hParams != NULL) {
        paramsPointer = hParams->getPointer();
        paramsSize = hParams->getSize();
    } else {
    	// 都为null时
        paramsPointer = nullptr;
    }

    // 对应buffer数据类型的分配大小
    OMX_U32 allottedSize;
    if (isMetadata) {
    	// 输入输出buffer端口时
    	// 就是计算每种buffer数据类型的结构占用内存大小
        if (mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource) {
            allottedSize = sizeof(VideoGrallocMetadata);
        } else if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer) {
            allottedSize = sizeof(VideoNativeMetadata);
        } else if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource) {
            allottedSize = sizeof(VideoNativeHandleMetadata);
        } else {
            return BAD_VALUE;
        }
    } else {
        // NULL params is allowed only in metadata mode.
        if (paramsPointer == nullptr) {
            ALOGE("b/25884056");
            return BAD_VALUE;
        }
        // 参数大小
        allottedSize = paramsSize;
    }

    // 是否为输出图形媒体元数据
    bool isOutputGraphicMetadata;
    if (portIndex == kPortIndexInputExtradata || portIndex == kPortIndexOutputExtradata) {
        isOutputGraphicMetadata = false;
    } else {
    	// true:输出buffer端口,且端口的媒体元数据buffer类型为这两种的其中一种时。否则为false
        isOutputGraphicMetadata = (portIndex == kPortIndexOutput) &&
                (mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource ||
                        mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer);
    }

    // 输出或输入端口请求分配的buffer位标志【值为0和1】,相当于端口索引
    uint32_t requiresAllocateBufferBit =
        (portIndex == kPortIndexInput)
            ? kRequiresAllocateBufferOnInputPorts
            : kRequiresAllocateBufferOnOutputPorts;

    // 注译:我们使用useBuffer来输出元数据,而不考虑【quirks】特殊配置信息
    // we use useBuffer for output metadata regardless of quirks
    if (!isOutputGraphicMetadata && (mQuirks & requiresAllocateBufferBit) &&
            portIndex != kPortIndexOutputExtradata &&
            portIndex != kPortIndexInputExtradata) {
        // 注译:元数据缓冲区buffer没有跨进程连接,如果不是元数据则只复制
        // metadata buffers are not connected cross process; only copy if not meta.
        // 此处创建BufferMeta即Buffer媒体元数据结构对象,内部管理不同参数数据类型
        buffer_meta = new BufferMeta(
                    params, hParams, portIndex, !isMetadata /* copy */, NULL /* data */);

        // 请求底层组件分配Buffer,这是个宏定义方法,最终还是会调用底层组件的对应方法【AllocateBuffer】
        // 这里就对应起来此前流程分析过的【appPrivate】程序私有数据类型字段,即它就是BufferMeta对象指针,allottedSize是它的数据大小
        // 举例SoftAVCDec组件实现结果为:
        // 底层基类会创建同样大小的内存buffer,然后更新对应端口索引的buffer信息,
        // 并会创建【header】数据类型对象并在其对应字段中缓存底层创建的内存buffer指针、
        // allottedSize、buffer_meta私有数据、端口索引等字段数据,并添加到底层组件对应端口缓冲区元数据【BufferInfo】中,
        // 最后检查底层状态扭转情况。
        err = OMX_AllocateBuffer(
                mHandle, &header, portIndex, buffer_meta, allottedSize);

        if (err != OMX_ErrorNone) {
            CLOG_ERROR(allocateBuffer, err,
                    SIMPLE_BUFFER(portIndex, (size_t)allottedSize,
                            paramsPointer));
        }
    } else {
    	// 否则,将会OMXNode节点实例中自身创建维护一个OMX数据buffer内存
        OMX_U8 *data = NULL;

        // metadata buffers are not connected cross process
        // use a backup buffer instead of the actual buffer
        // 使用一个备份buffer来代替实际buffer
        if (isMetadata) {
        	// 是媒体元数据时,创建这么大字节的数据内存
            data = new (std::nothrow) OMX_U8[allottedSize];
            if (data == NULL) {
                return NO_MEMORY;
            }
            // 字节内存全设置0
            memset(data, 0, allottedSize);

            // 创建它,此处可以看出来,这种情况创建的数据内存将设置给BufferMeta来管理
            buffer_meta = new BufferMeta(
                    params, hParams, portIndex, false /* copy */, data);
        } else {
        	// 非媒体元数据时
        	// 直接使用IMemory、IHidlMemory这两种buffer数据类型中的数据地址指针,
        	// 也就相当于它们此时共用指针来访问相同内存数据
            data = static_cast<OMX_U8 *>(paramsPointer);

            // 所以此时创建BufferMeta就不再需要传入data了
            // 备注:其实最后一个参数数据指针data,只是个备份数据,看实现未使用到
            buffer_meta = new BufferMeta(
                    params, hParams, portIndex, false /* copy */, NULL);
        }

        // 宏定义方法,将会执行底层组件该方法,让其使用OMXNode中创建的数据
        // 举例SoftAVCDec组件实现结果:
        // 其实和上面的allocateBuffer方法基本一样处理,
        // 只是有一点不同是不需要底层组件创建【allottedSize】大小的【data】,因为【data】上层已创建好了
        err = OMX_UseBuffer(
                mHandle, &header, portIndex, buffer_meta,
                allottedSize, data);

        if (err != OMX_ErrorNone) {
            CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(
                    portIndex, (size_t)allottedSize, data));
        }
    }

    if (err != OMX_ErrorNone) {
        delete buffer_meta;
        buffer_meta = NULL;

        *buffer = 0;

        return StatusFromOMXError(err);
    }

    // 此处也再次表明:Buffer头数据中私有数据pAppPrivate字段值必须为buffer_meta数据类型,
    // 这一步就是底层组件创建header对象时完成的
    CHECK_EQ(header->pAppPrivate, buffer_meta);
    // 备注:其实从上面的处理流程可知,这个Buffer header头信息结构对象是非常重要的,
    // 它缓存并控制管理关联了上层和底层组件的Buffer,我们可以通过它来完成端口buffer数据的关联和转换

    // 创建一个Buffer id
    // 这一步也是非常重要的,因为编解码器就是通过Buffer id来控制输入输出端口缓冲区buffer来实现的
    // 见下面分析
    *buffer = makeBufferID(header);

    // 添加端口索引和buffer id到指定buffer端口的活动(正在使用的)Buffer队列中
    // 见下面分析
    addActiveBuffer(portIndex, *buffer);

    // 根据此前流程中的分析,可知该参数解码器时通常为空,请见此前分析
    // 此时也就是如果设置了输入Surface的话,该Surface将会通过Buffer ID直接来接管输入Buffer
    // 暂不展开分析
    sp<IOMXBufferSource> bufferSource(getBufferSource());
    if (bufferSource != NULL && portIndex == kPortIndexInput) {
        bufferSource->onInputBufferAdded(*buffer);
    }

    CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT(
            *buffer, portIndex, "%u(%zu)@%p", allottedSize, paramsSize, paramsPointer));
    return OK;
}

makeBufferID(header)实现分析:
创建一个Buffer ID
这一步也是非常重要的,因为编解码器就是通过Buffer id来控制输入输出端口缓冲区buffer来实现的

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
IOMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
    if (bufferHeader == NULL) {
        return 0;
    }
    // ID加锁
    Mutex::Autolock autoLock(mBufferIDLock);
    IOMX::buffer_id buffer;
    do { // handle the very unlikely case of ID overflow
    	// 处理极不可能的ID溢出情况
    	// Buffer ID计数器值,默认为0,从0开始计数
        if (++mBufferIDCount == 0) {
        	// 此处if内,若发生32位Int溢出时,则会再次从0开始计数
            ++mBufferIDCount;
        }
        // 强转得到ID
        buffer = (IOMX::buffer_id)mBufferIDCount;
        // 再次循环条件判断产生的buffer id是否有效,若已存在则继续下一个
        // 备注:mBufferIDToBufferHeader根据名称就知它相当于是个map功能
    } while (mBufferIDToBufferHeader.indexOfKey(buffer) >= 0);
    // ID有效则缓存它和当前Buffer header头信息指针的映射关系,
    // 备注:也就是说后续编解码开始工作时上层和底层都会通过Buffer ID来获取对应的buffer
    mBufferIDToBufferHeader.add(buffer, bufferHeader);
    // 这也是一个map功能,不过刚好和上面相反存储而已
    mBufferHeaderToBufferID.add(bufferHeader, buffer);
    // 返回ID
    return buffer;
}

addActiveBuffer(portIndex, *buffer)实现分析:
添加端口索引和buffer id到指定buffer端口的活动(正在使用的)Buffer队列中,其实际上是创建一个ActiveBuffer结构对象来存储端口索引和buffer id映射关系

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, IOMX::buffer_id id) {
	// 创建活动Buffer结构对象,保存并添加到活动Buffer队列中
    ActiveBuffer active;
    active.mPortIndex = portIndex;
    active.mID = id;
    mActiveBuffers.push(active);

    if (portIndex == kPortIndexInputExtradata || portIndex == kPortIndexOutputExtradata) {
        // Allow extradata ports
    } else if (portIndex < NELEM(mNumPortBuffers)) {
    	// mNumPortBuffers数组的大小为2,此处检查索引必须为输入或输出端口索引时才进入
    	// 递增对应输入或输出端口的Buffer个数,其实际就是记录当前每个端口的Buffer个数
        ++mNumPortBuffers[portIndex];
    }
}

8.3.2.4.2、useGraphicBuffer_l(portIndex, omxBuffer.mGraphicBuffer, buffer)实现分析:
使用图形Buffer
由于本章节接下来内容篇幅过长,因此必须放入另一章节分析,请查看:
【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 4】【06】

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值