/****************************************************************************** * * Copyright 2007, Silicon Image, Inc. All rights reserved. * No part of this work may be reproduced, modified, distributed, transmitted, * transcribed, or translated into any language or computer format, in any form * or by any means without written permission of: Silicon Image, Inc., 1060 * East Arques Avenue, Sunnyvale, California 94085 * *****************************************************************************/ /** * @file media_buffer_pool.c * * @brief * Buffer Pool implementation * *
 *
 *   Principal Author: Joerg Detert
 *   Creation date:    Feb 28, 2008
 *
 * 
* *****************************************************************************/ #include #include "media_buffer_pool.h" #define MEDIA_BUF_ALIGN(buf, align) (((buf)+((align)-1U)) & ~((align)-1U)) /****************************************************************************** * MediaBufPoolGetSize *****************************************************************************/ RESULT MediaBufPoolGetSize(MediaBufPoolConfig_t* pPoolConfig) { RESULT ret = RET_SUCCESS; if(pPoolConfig == NULL) { return RET_WRONG_HANDLE; } if(pPoolConfig->bufNum > pPoolConfig->maxBufNum) { return RET_WRONG_CONFIG; } /* size of extra metadata */ pPoolConfig->metaDataMemSize = pPoolConfig->maxBufNum * pPoolConfig->metaDataSizeMediaBuf; /* size of media buffer array */ pPoolConfig->metaDataMemSize += (uint32_t)(pPoolConfig->maxBufNum * sizeof(MediaBuffer_t)); /* calculate size of buffer array*/ if(pPoolConfig->flags & (uint32_t)BUFPOOL_RINGBUFFER) { /* results in no gaps between buffers but an offset depending on the alignment */ pPoolConfig->bufMemSize = (pPoolConfig->maxBufNum * pPoolConfig->bufSize) + pPoolConfig->bufAlign; /* the buffer size must be correct to the alignment otherwise we would have * unaligned buffers after the first which is always aligned */ if((pPoolConfig->bufSize & ((uint32_t)pPoolConfig->bufAlign - 1U)) != 0U) { return RET_WRONG_CONFIG; } } else { /* this leads to gaps between the buffers dependend on the alignment */ pPoolConfig->bufMemSize = pPoolConfig->maxBufNum * (pPoolConfig->bufSize + pPoolConfig->bufAlign); } return ret; } /****************************************************************************** * MediaBufPoolCreate *****************************************************************************/ RESULT MediaBufPoolCreate(MediaBufPool_t* pBufPool, MediaBufPoolConfig_t* pPoolConfig, MediaBufPoolMemory_t poolMemory) { uint32_t i; uint32_t offset; void* pBuf; RESULT ret = RET_SUCCESS; if(pBufPool == NULL) { return RET_WRONG_HANDLE; } if((poolMemory.pMetaDataMemory == NULL) || (poolMemory.pBufferMemory == NULL)) { return RET_INVALID_PARM; } if((pPoolConfig->bufNum == 0U) || (pPoolConfig->bufSize == 0U) || (pPoolConfig->maxBufNum < pPoolConfig->bufNum)) { return RET_WRONG_CONFIG; } /* If buffer pool is switched to ringbuffer mode, there must not be any gap*/ /* between individual buffers inside static buffer pool, introduced by data*/ /* alignement issues (e.g. rouding up of internal buffer sizes).*/ /* That is, the buffer size must be a multiple of the data alignement.*/ if((pPoolConfig->flags & BUFPOOL_RINGBUFFER) && (pPoolConfig->bufSize % pPoolConfig->bufAlign)) { return RET_WRONG_CONFIG; } /* initialize buffer pool object*/ (void) memset(pBufPool, 0, sizeof(MediaBufPool_t)); pBufPool->bufSize = pPoolConfig->bufSize; pBufPool->metaDataSizeMediaBuf = pPoolConfig->metaDataSizeMediaBuf; pBufPool->bufNum = pPoolConfig->bufNum; pBufPool->freeBufNum = pPoolConfig->bufNum; pBufPool->maxBufNum = pPoolConfig->maxBufNum; pBufPool->poolSize = pPoolConfig->bufNum * pPoolConfig->bufSize; pBufPool->flags = pPoolConfig->flags; /* The memory given by the caller is assigned to the buffer pool */ pBufPool->pBaseAddress = poolMemory.pMetaDataMemory; /* Make sure that sizes in pPoolConfig are written */ (void) MediaBufPoolGetSize(pPoolConfig); /* initialize buffer memory to zero */ (void) memset(poolMemory.pMetaDataMemory, 0, (size_t) pPoolConfig->metaDataMemSize); /* We use the first partition of memory for the media buffer array */ pBufPool->pBufArray = (MediaBuffer_t*) pBufPool->pBaseAddress; /* The second partition of memory is used for the buffer meta data array for Media Buffers */ offset = (pPoolConfig->maxBufNum * sizeof(MediaBuffer_t)); pBufPool->pMetaDataMediaBufBase = (void*) (((ulong_t) pBufPool->pBaseAddress) + offset); /* The memory pointed to by pBufferMemory is used for * the real buffer memory. This memory is assigned to the pointers stored in the corresponding * MediaBuffer_t[]. Due to the alignment restrictions given by the user it must be kept in mind * that the alignment is added. */ pBuf = poolMemory.pBufferMemory; for(i = 0U; i < pBufPool->maxBufNum; i++) { /* set base address of buffer (will be changed in case that buffer pool is resized) */ pBufPool->pBufArray[i].pBaseAddress = (uint8_t*) MEDIA_BUF_ALIGN((ulong_t)pBuf + (i * pPoolConfig->bufSize), (uint32_t)pPoolConfig->bufAlign); /* set base size of buffer (will be changed in case that buffer pool is resized) */ pBufPool->pBufArray[i].baseSize = pBufPool->bufSize; if ( pPoolConfig->metaDataSizeMediaBuf != 0 ) { /* set Media Buffer meta data structure address for (stays the same during lifetime of buffer pool) */ pBufPool->pBufArray[i].pMetaData = (void *)((ulong_t) pBufPool->pMetaDataMediaBufBase + (i * pPoolConfig->metaDataSizeMediaBuf)); } else { pBufPool->pBufArray[i].pMetaData = NULL; } MediaBufInit(&pBufPool->pBufArray[i]); } AtomicMutexInit(); return ret; } /****************************************************************************** * MediaBufPoolDestroy *****************************************************************************/ RESULT MediaBufPoolDestroy(MediaBufPool_t *pBufPool) { DCT_ASSERT(pBufPool != NULL); (void) memset(pBufPool, 0, sizeof(MediaBufPool_t)); AtomicMutexDestory(); return RET_SUCCESS; } /****************************************************************************** * MediaBufPoolReset *****************************************************************************/ RESULT MediaBufPoolReset(MediaBufPool_t* pBufPool) { uint32_t i; DCT_ASSERT(pBufPool != NULL); /* reset state variables */ pBufPool->freeBufNum = pBufPool->bufNum; pBufPool->fillLevel = 0; pBufPool->index = 0; /* re-init media buffers */ for(i = 0U; i < pBufPool->maxBufNum; i++) { MediaBufInit(&pBufPool->pBufArray[i]); } return RET_SUCCESS; } /****************************************************************************** * MediaBufPoolRegisterCb *****************************************************************************/ RESULT MediaBufPoolRegisterCb(MediaBufPool_t* pBufPool, MediaBufPoolCbNotify_t fpCallback, void* pUserContext) { RESULT ret = RET_NOTAVAILABLE; int32_t i; if(pBufPool == NULL) { return RET_WRONG_HANDLE; } if(fpCallback == NULL) { return RET_INVALID_PARM; } if(pBufPool->notify.fpCallback == NULL) { pBufPool->notify.fpCallback = fpCallback; pBufPool->notify.pUserContext = pUserContext; ret = RET_SUCCESS; } return ret; } /****************************************************************************** * MediaBufPoolDeregisterCb *****************************************************************************/ RESULT MediaBufPoolDeregisterCb(MediaBufPool_t* pBufPool, MediaBufPoolCbNotify_t fpCallback) { RESULT ret = RET_NOTAVAILABLE; int32_t i; if(pBufPool == NULL) { return RET_WRONG_HANDLE; } if(fpCallback == NULL) { return RET_INVALID_PARM; } if(pBufPool->notify.fpCallback == fpCallback) { pBufPool->notify.fpCallback = NULL; pBufPool->notify.pUserContext = NULL; ret = RET_SUCCESS; } return ret; } /****************************************************************************** * MediaBufPoolGetBuffer *****************************************************************************/ MediaBuffer_t* MediaBufPoolGetBuffer(MediaBufPool_t* pBufPool) { MediaBuffer_t *pMediaBuffer; DCT_ASSERT(pBufPool != NULL); for(;;) { /* if the requested number of buffers is greater than the maximum then wait*/ while( pBufPool->freeBufNum == 0U ) { return NULL; } /* at least one buffer is free*/ for(;;) { if(!pBufPool->pBufArray[pBufPool->index].lockCount) { /* adjust the resources count*/ pBufPool->freeBufNum--; pBufPool->pBufArray[pBufPool->index].lockCount = 1; pBufPool->pBufArray[pBufPool->index].pOwner = pBufPool; pMediaBuffer = &pBufPool->pBufArray[pBufPool->index]; if(++(pBufPool->index) >= pBufPool->bufNum) { pBufPool->index = 0U; } return pMediaBuffer; } else { /* pBufPool->uiIndex points to the next buffer to be checked for a get empty request.*/ /* If that buffer is locked, no media buffer is returned, because random access is*/ /* not allowed in ringbuffer mode.*/ if(pBufPool->flags & BUFPOOL_RINGBUFFER) { return NULL; } } if(++(pBufPool->index) >= pBufPool->bufNum) { pBufPool->index = 0U; } } } /* for( ;;)*/ } /****************************************************************************** * MediaBufPoolFreeBuffer *****************************************************************************/ void MediaBufPoolFreeBuffer(MediaBufPool_t* pBufPool, MediaBuffer_t *pBuf) { int32_t i; DCT_ASSERT(pBufPool != NULL); DCT_ASSERT(pBuf != NULL); pBuf->lockCount = 0; pBufPool->freeBufNum++; if(pBufPool->notify.fpCallback != NULL) { (pBufPool->notify.fpCallback)(pBufPool->notify.pUserContext, pBuf); } }