高通Camera Stream buffer 通过ion分配原理

首先分析从QCameraStream的getBufs这个函数开始。

int32_t QCameraStream::getBufs(cam_frame_len_offset_t *offset,
        uint8_t *num_bufs,
        uint8_t **initial_reg_flag,
        mm_camera_buf_def_t **bufs,
        mm_camera_map_unmap_ops_tbl_t *ops_tbl)
{

 ...

   //Allocate stream buffer
    mStreamBufs = mAllocator.allocateStreamBuf(mStreamInfo->stream_type,
            mFrameLenOffset.frame_len, mFrameLenOffset.mp[0].stride,
            mFrameLenOffset.mp[0].scanline, numBufAlloc, mStreamInfo->cam_type);//分配QCameraMemory对象,封装ion的分配管理过程。
    if (!mStreamBufs) {
        LOGE("Failed to allocate stream buffers");
        return NO_MEMORY;
    }

...

}

allocateStreamBuf在QCamera2HardwareInterface中定义。

QCameraMemory *QCamera2HardwareInterface::allocateStreamBuf(
        cam_stream_type_t stream_type, size_t size, int stride, int scanline,
        uint8_t &bufferCnt, uint32_t cam_type)
{

...

    case CAM_STREAM_TYPE_RAW:
        if(isSecureMode()) {
...
        } else {
            mem = new QCameraStreamMemory(mGetMemory,
                    mCallbackCookie,
                    bCachedMem,
                    (bPoolMem) ? &m_memoryPool : NULL,
                    stream_type);//创建QCameraMemory子对象QCameraStreamMemory
        }
        break;

...

    if (bufferCnt > 0) {
        rc = mem->allocate(bufferCnt, size);//分配内存
        if (rc < 0) {
            delete mem;
            return NULL;
        }
        bufferCnt = mem->getCnt();
    }

...

}

QCameraMemory的allocate函数

int QCameraHeapMemory::allocate(uint8_t count, size_t size)
{

...

else{
        rc = alloc(count, size, heap_id_mask);//调用alloc适配函数分配内存
        if (rc < 0) {
            ATRACE_END();
            return rc;
        }

        for (int i = 0; i < count; i ++) {
            void *vaddr = mmap(NULL,
                        mMemInfo[i].size,
                        PROT_READ | PROT_WRITE,
                        MAP_SHARED,
                        mMemInfo[i].fd, 0);//通过fd,映射内核内存地址到用户空间,
            if (vaddr == MAP_FAILED) {
                for (int j = i-1; j >= 0; j --) {
                    munmap(mPtr[j], mMemInfo[j].size);
                    mPtr[j] = NULL;
                    deallocOneBuffer(mMemInfo[j]);
                }
                // Deallocate remaining buffers that have already been allocated
                for (int j = i; j < count; j++) {
                    deallocOneBuffer(mMemInfo[j]);
                }
                ATRACE_END();
                return NO_MEMORY;
            } else
                mPtr[i] = vaddr;//并将用户空间地址保存于mPtr数组中,供后续使用
        }
    }

...

}

QCameraMemory的分配函数

int QCameraMemory::alloc(int count, size_t size, unsigned int heap_id)
{

...

  for (int i = mBufferCount; i < new_bufCnt; i ++){
        if ( NULL == mMemoryPool ) {
            LOGH("No memory pool available, allocating now");
            rc = allocOneBuffer(mMemInfo[i], heap_id, size, m_bCached,
                     secure_mode);//调用ion操作函数接口分配内存,fd等信息保存在mMemInfo中,后续再用ion通过fd操作内存。
            if (rc < 0) {
                LOGE("AllocateIonMemory failed");
                for (int j = i-1; j >= 0; j--)
                    deallocOneBuffer(mMemInfo[j]);
                break;
            }
        } else {//另一种分配方式,暂不研究
            rc = mMemoryPool->allocateBuffer(mMemInfo[i],
                                             heap_id,
                                             size,
                                             m_bCached,
                                             mStreamType,
                                             secure_mode);
            if (rc < 0) {
                LOGE("Memory pool allocation failed");
                for (int j = i-1; j >= 0; j--)
                    mMemoryPool->releaseBuffer(mMemInfo[j],
                                               mStreamType);
                break;
            }
        }

    }

...

}

调用ion分配内存的函数

int QCameraMemory::allocOneBuffer(QCameraMemInfo &memInfo,
        unsigned int heap_id, size_t size, bool cached, bool secure_mode)

{
    int rc = OK;
    struct ion_handle_data handle_data;
    struct ion_allocation_data alloc;
    struct ion_fd_data ion_info_fd;
    int main_ion_fd = -1;

    main_ion_fd = open("/dev/ion", O_RDONLY);//第一步:创建ion client
    if (main_ion_fd < 0) {
        LOGE("Ion dev open failed: %s\n", strerror(errno));
        goto ION_OPEN_FAILED;
    }

    memset(&alloc, 0, sizeof(alloc));//第二步:设置struct ion_allocation_data alloc;进行内存分配,获取handle句柄
    alloc.len = size;//1.分配的大小
    /* to make it page size aligned */
    alloc.len = (alloc.len + 4095U) & (~4095U);
    alloc.align = 4096;//2.对齐字节
    if (cached) {
        alloc.flags = ION_FLAG_CACHED;
    }
    alloc.heap_id_mask = heap_id;//3.分配的内存类型camera,display等
    if (secure_mode) {
        LOGD("Allocate secure buffer\n");
        if (QCameraCommon::is_target_SDM450())
            alloc.heap_id_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
        else
            alloc.heap_id_mask = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID);
        alloc.flags = ION_FLAG_SECURE | ION_FLAG_CP_CAMERA;
        alloc.align = 2097152; // 2 MiB alignment to be able to protect later
        alloc.len = (alloc.len + 2097152U) & (~2097152U);
    }

    rc = ioctl(main_ion_fd, ION_IOC_ALLOC, &alloc);//调用ioctl执行分配
    if (rc < 0) {
        LOGE("ION allocation failed: %s\n", strerror(errno));
        goto ION_ALLOC_FAILED;
    }

    memset(&ion_info_fd, 0, sizeof(ion_info_fd));//第三步:设置struct ion_info_fd获取fd 为下一步作map用
    ion_info_fd.handle = alloc.handle;//设置已分配内存的句柄
    rc = ioctl(main_ion_fd, ION_IOC_SHARE, &ion_info_fd);//调用ioctl 用ION_IOC_SHARE命令获取fd
    if (rc < 0) {
        LOGE("ION map failed %s\n", strerror(errno));
        goto ION_MAP_FAILED;
    }

    memInfo.main_ion_fd = main_ion_fd;//分配的内存信息保存于QCameraMemInfo,供后续使用。
    memInfo.fd = ion_info_fd.fd;
    memInfo.handle = ion_info_fd.handle;
    memInfo.size = alloc.len;
    memInfo.cached = cached;
    memInfo.heap_id = heap_id;

    LOGH("ION buffer %lx with size %d allocated memInfo.fd: %d main_ion_fd: %d",
            (unsigned long)memInfo.handle, alloc.len, memInfo.fd, main_ion_fd);
    return OK;

ION_MAP_FAILED:
    memset(&handle_data, 0, sizeof(handle_data));
    handle_data.handle = ion_info_fd.handle;
    ioctl(main_ion_fd, ION_IOC_FREE, &handle_data);
ION_ALLOC_FAILED:
    close(main_ion_fd);
ION_OPEN_FAILED:
    return NO_MEMORY;
}

你可能感兴趣的:(Camera,视频多媒体)