环形内存,circle memory

typedef struct tagONLY_CIRCLE_MEM
{
 UINT32 nMemSize;
 UINT8 *pBuf;
 UINT8 *pWrite;
 UINT8 *pRead;
 BOOL   bTag; //
是否pWrite是在pRead之后
#ifdef WIN32
 HMUTEX hBufMutex;
#elif _LINUX
 pthread_mutex_t hBufMutex;
#endif
}ONLY_CIRCLE_MEM PACKED;

typedef void* HOCM

 


HOM  ocmAlloc(UINT32 nMemSize)
{
 ONLY_CIRCLE_MEM *pOCM = malloc(sizeof(ONLY_CIRCLE_MEM));
 if(pOCM==NULL)
  return NULL;
 pOCM->pBuf = malloc(nMemSize);
 if(pOCM->pBuf==NULL)
 {
  free(pOCM);
  return NULL;
 }
 pOCM->pWrite = pOCM->pBuf;
 pOCM->pRead = pOCM->pBuf;
 pOCM->nMemSize = nMemSize;
 pOCM->bTag = TRUE;
#ifdef WIN32
 pOCM->hBufMutex=CreateMutex(NULL, FALSE, NULL);
#elif _LINUX
 pOCM->hBufMutex =  (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
#endif
 return pOCM;
}

void ocmFree(HOCM hocm)
{
 ONLY_CIRCLE_MEM *pOCM =(ONLY_CIRCLE_MEM*)hocm;
 if(pOCM==NULL)
  return;
#ifdef WIN32
 CloseHandle(pOCM->hBufMutex);
#elif _LINUX
 pthread_mutex_destroy(&pOCM->hBufMutex);
#endif 
 if(pOCM->pBuf!=NULL)
 {
  free(pOCM->pBuf);
 }
 pOCM->pRead = NULL;
 pOCM->pWrite = NULL;
 free(pOCM);
}

UINT32  ocmPut(HOCM hocm, void *pBuf, UINT32 nBufLen)
{
 ONLY_CIRCLE_MEM *pOCM = (ONLY_CIRCLE_MEM*)hocm;
 UINT32 nLeftLen=nBufLen;
 INT32 rc;

 if(pOCM==NULL || pOCM->pBuf ==NULL)
 {
  return 0;
 }

#ifdef WIN32
 WaitForSingleObject(pOCM->hBufMutex, INFINITE);
#elif _LINUX
 rc = pthread_mutex_lock(&pOCM->hBufMutex);
 if(rc)
 {
  printf("Cannot lock the thread mutex\n");
  pthread_exit(NULL);
 }
#endif

 while(nLeftLen>0)
 {
  if(pOCM->bTag)
  {
   if(  
pOCM ->pBuf+pOCM->nMemSize-pOCM->pWrite>nLeftLen)
   {
    memcpy(pOCM->pWrite, (UINT8*)pBuf+(nBufLen-nLeftLen), nLeftLen);
    pOCM->pWrite += nLeftLen;
    nLeftLen = 0;
   }
   else
   {
    memcpy(pOCM->pWrite, (UINT8*)pBuf+(nBufLen-nLeftLen), pOCM->pBuf+pOCM->nMemSize-pOCM->pWrite);
    nLeftLen -= pOCM->pBuf+pOCM->nMemSize-pOCM->pWrite;
    pOCM->pWrite = pOCM->pBuf;
    pOCM->bTag = FALSE;
   }
  }
  else
  {
   if(pOCM->pRead-pOCM->pWrite>nLeftLen)
   {
    memcpy(pOCM->pWrite, (UINT8*)pBuf+(nBufLen-nLeftLen), nLeftLen);
    pOCM->pWrite += nLeftLen;
    nLeftLen=0;
   }
   else
   {
    memcpy(pOCM->pWrite, (UINT8*)pBuf+(nBufLen-nLeftLen), pOCM->pRead-pOCM->pWrite);
    nLeftLen -= pOCM->pRead-pOCM->pWrite;
    pOCM->pWrite = pOCM->pRead;
    break;
   }
   
  }
 }

#ifdef WIN32
 ReleaseMutex(pOCM->hBufMutex);   
#elif _LINUX
 rc = pthread_mutex_unlock(&pOCM->hBufMutex);
 if(rc)
 {
  printf("Cannot unlock the thread mutex\n");
  pthread_exit(NULL);
 }
#endif
 return nBufLen-nLeftLen;
}

UINT32 ocmGet(HOM hocm, void *pBuf, UINT32 nDataLen)
{
 ONLY_CIRCLE_MEM *pOCM = (ONLY_CIRCLE_MEM*)hocm;
 UINT32 nLeftLen=nDataLen;
 INT32 rc;
 if(pOCM==NULL ||pOCM->pBuf==NULL)
 {
  return 0;
 }
#ifdef WIN32
 WaitForSingleObject(pOCM->hBufMutex, INFINITE);
#elif _LINUX
 rc = pthread_mutex_lock(&pOCM->hBufMutex);
 if(rc)
 {
  printf("Cannot lock the thread mutex\n");
  pthread_exit(NULL);
 }
#endif 
 while(nLeftLen>0)
 {
  if(pOCM->bTag)
  {
   if(pOCM->pWrite-pOCM->pRead >nLeftLen)
   {
    memcpy((UINT8*)pBuf+(nDataLen-nLeftLen), pOCM->pRead, nLeftLen);
    pOCM->pRead += nLeftLen;
    nLeftLen = 0;
   }
   else
   {
    memcpy((UINT8*)pBuf+(nDataLen-nLeftLen), pOCM->pRead, pOCM->pWrite-pOCM->pRead);
    nLeftLen -= (pOCM->pWrite-pOCM->pRead);
    pOCM->pRead = pOCM->pWrite;
    break;
   }
  }
  else
  {
   if(pOCM->pBuf+pOCM->nMemSize-pOCM->pRead>nLeftLen)
   {
    memcpy((UINT8*)pBuf+(nDataLen-nLeftLen), pOCM->pRead, nLeftLen);
    pOCM->pRead+=nLeftLen;
    nLeftLen=0;
   }
   else
   {
    memcpy((UINT8*)pBuf+(nDataLen-nLeftLen), pOCM->pRead, pOCM->pBuf+pOCM->nMemSize-pOCM->pRead);
    nLeftLen -= pOCM->pBuf+pOCM->nMemSize-pOCM->pRead;
    pOCM->pRead = pOCM->pBuf;
    pOCM->bTag = TRUE;
   }

  }
 }
#ifdef WIN32
 ReleaseMutex(pOCM->hBufMutex);   
#elif _LINUX
 rc = pthread_mutex_unlock(&pOCM->hBufMutex);
 if(rc)
 {
  printf("Cannot unlock the thread mutex\n");
  pthread_exit(NULL);
 }
#endif
 return nDataLen-nLeftLen;
}

只给出部分代码,不讲解。注意开头的那个结构体中的BOOL   bTag; 的重要作用
/** * 从base_addr地址开始搜索可用的buffer,可能会绕圈,参考nvr bq实现 * * NOTE: 原本通过遍历unit寻找可用buffer,但发现效率以及潜在问题,改为遍历block寻找可用buffer * buffer的申请以block为单位,并以确保一个block(GOP)的完整性为基础进行空闲buffer的寻找,否 * 则涉及到unit层会变的比较复杂,且可能出现以帧为单位的消费者在发生覆盖的情况下,拿到下一个帧 * 时非当前GOP的P帧,具体情况后续分析 */ static S32 __get_available_buffer(avdm_context_t *ctx, U8 *base_addr, U32 len, U32 unit_len) { S32 tail_avail_len = (S32)ctx->buffer + (S32)ctx->buffer_size - (S32)base_addr; block_desc_t *bdesc = NULL; avdm_block_t *block = NULL; avdm_ring_t *ring = ctx->ring; U32 i = 0, j = 0; S32 tmp_len = 0, tmp_min_len = 0; U32 memNo = 0, attached_cnt = 0; memobj_t memobj[AVDM_BLOCK_RING_MAX_SIZE + 1] = {}; /* 用来表示空闲内存的数组 */ memobj_t *tmp_memobj = NULL, *cur_memobj = NULL; BOOL search_circle_round_first_time = TRUE; if (tail_avail_len < 0) return ERROR; /* 要搜索的block长度比当前unit长度还要小,出现这种情况时把block长度加上unit长度再去搜索 */ if (len < unit_len) { len += unit_len; } /* 1. 首先看base_addr后的空间是不是满足要求 */ /* 不考虑被引用的block,buffer后面剩余空间已经不够 */ if (tail_avail_len < len) goto search_circle_round; /* 遍历被锁定的block,如果base_addr后面所有attached block到base_addr都大于申请长度,认为具有空间 */ FOR_EACH_OCCUPIED_BLOCK(ring, bdesc, i) { if (!BLOCK_IS_LOCKED(bdesc)) continue; tmp_len = (S32)bdesc->block.addr - (S32)base_addr; if (tmp_len >= 0 && tmp_len < len) goto search_circle_round; if ((tmp_len >= 0) && (tmp_min_len == 0 || tmp_min_len > tmp_len)) tmp_min_len = tmp_len; } /* 保存当前block起始地址和可用长度 */ ctx->ring->bbuffer.addr = base_addr; ctx->ring->bbuffer.available_len = len; // 在每次block_start时,len = ring->block_max_size = AVDM_AUDIO_BLOCK_MAX_SIZE if (tmp_min_len) ctx->ring->bbuffer.potential_len = tmp_min_len; else ctx->ring->bbuffer.potential_len = (U32)tail_avail_len; return OK; search_circle_round: /* 2. 进一步寻找可用内存 */ /* 根据block环获取所有的free buf,最多有AVDM_UNIT_RING_SIZE+1个memobj */ memobj[0].ptr = ctx->buffer; memobj[0].len = ctx->buffer_size; memobj[0].next = NULL; memNo = 1; attached_cnt = 0; FOR_EACH_OCCUPIED_BLOCK(ring, bdesc, i) { if (search_circle_round_first_time) { /* 第一次执行该循环,如果block被锁定,就用来计算memobj */ if (!BLOCK_IS_LOCKED(bdesc)) continue; } else { /* 非第一次执行该循环,仅block的buffer被锁定时,用来计算memobj */ if (!BLOCK_BUFFER_IS_LOCKED(bdesc)) continue; } block = &bdesc->block; attached_cnt++; for (j = 0; j < memNo; j ++) { /* 查找被分隔的memobj */ if ((block->addr >= memobj[j].ptr) && (block->addr < memobj[j].ptr + memobj[j].len)) { /* split memobj[j] */ memobj[memNo].ptr = block->addr + block->len; memobj[memNo].len = memobj[j].ptr + memobj[j].len - memobj[memNo].ptr; memobj[j].len = block->addr - memobj[j].ptr; /* insert newmemobj */ memobj[memNo].next = memobj[j].next; memobj[j].next = &memobj[memNo]; memNo++; break; } } /* This should not happend. Attached mem is NOT in pool. */ if (j == memNo) { for (j = 0; j < memNo; j++) AVDM_ERROR("memobj: %#x-%#x, len %#x", (U32)memobj[j].ptr, (U32)memobj[j].ptr + memobj[j].len, memobj[j].len); AVDM_ERROR("Fatal error: Invalid block: %#x-%#x, len %#x", (U32)block->addr, (U32)block->addr + block->len, block->len); } } /* 3. 查找base_addr所在memobj */ for (i = 0, tmp_memobj = memobj; i < memNo; i++, tmp_memobj = tmp_memobj->next) { if ((base_addr >= tmp_memobj->ptr) && (base_addr <= tmp_memobj->ptr + tmp_memobj->len)) { cur_memobj = tmp_memobj; break; } } /* 当前地址不属于任何一个memobj,该情况不应该发生 */ if (NULL == cur_memobj) { AVDM_ERROR("Fatal error: base addr not found in any memobj"); return ERROR; } /* 4. 从查找到的memobj之后寻找长度为len的空间 */ tmp_memobj = cur_memobj; for (i = 0; i < memNo; i++) { tmp_memobj = tmp_memobj->next; if (tmp_memobj == NULL) tmp_memobj = memobj; if (tmp_memobj->len >= len) { ctx->ring->bbuffer.addr = tmp_memobj->ptr; ctx->ring->bbuffer.available_len = len; ctx->ring->bbuffer.potential_len = tmp_memobj->len; return OK; } } /* 5. 所有memobj仍然不满足长度为len的空间,只去寻找足够存放当前帧的空间 */ AVDM_WARN("Maybe attached too much, %d. Wanna avdm%d block size %#x, but failed.", attached_cnt, ctx->type, len); tmp_memobj = cur_memobj; for (i = 0; i < memNo; i++) { tmp_memobj = tmp_memobj->next; if (tmp_memobj == NULL) tmp_memobj = memobj; if (tmp_memobj->len >= unit_len) { ctx->ring->bbuffer.addr = tmp_memobj->ptr; /* 可用内存直接使用memobj长度而非单独的unit长度,减少后续更新可用内存的频率 */ ctx->ring->bbuffer.available_len = tmp_memobj->len; ctx->ring->bbuffer.potential_len = tmp_memobj->len; return OK; } } /* 6. 当前帧的空间都无法满足,返回步骤2重新搜索,但排除仅block desc被占用的情况 */ if (search_circle_round_first_time) { search_circle_round_first_time = FALSE; goto search_circle_round; } /* 没有足够的memory,dump memobj */ AVDM_ERROR("Maybe attached too much, %d. Wanna avdm%d unit size %#x, but failed.", attached_cnt, ctx->type, unit_len); for (i=0, tmp_memobj=memobj; (i<memNo)&&(tmp_memobj!=NULL); i++, tmp_memobj=tmp_memobj->next) AVDM_ERROR("memobj: [%d] %#x-%#x, len %#x", ((U32)tmp_memobj-(U32)memobj)/sizeof(memobj_t), (U32)tmp_memobj->ptr-(U32)ctx->buffer, (U32)tmp_memobj->ptr + tmp_memobj->len-(U32)ctx->buffer, tmp_memobj->len); return ERROR; }解析代码
最新发布
10-31
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值