CRITICAL_SECTION g_CriticalSection = {0};

char gStreamBuffer[STREAM_BUFFER_LEN];
static char* pStreamBegin = gStreamBuffer;
static char* pStreamEnd = gStreamBuffer;
int putStreamData(LPBYTE p, DWORD len)
{
    EnterCriticalSection(&g_CriticalSection);
    if((pStreamEnd < gStreamBuffer)||(pStreamEnd >= gStreamBuffer + STREAM_BUFFER_LEN))
    {
        printf("invalid pointer pStreamEnd\n");
        return -1;//invalid pointer
    }
    if((pStreamBegin < gStreamBuffer)||(pStreamBegin >= gStreamBuffer + STREAM_BUFFER_LEN))
    {
        printf("invalid pointer pStreamBegin\n");
        return -1;//invalid pointer
    }

    
    if(pStreamEnd >= pStreamBegin)
    {
        //normal case
        if((len + pStreamEnd - pStreamBegin) > STREAM_BUFFER_LEN)
        {
            printf("Input stream is too long 1, pointer = 0x%x, length = %d, buffer available bytes %d \n", p, len, STREAM_BUFFER_LEN + pStreamBegin - pStreamEnd);
            LeaveCriticalSection(&g_CriticalSection);
            return -1;//over flow
        }
        //now we can receive the data from tuner
        if((pStreamEnd + len) < (gStreamBuffer + STREAM_BUFFER_LEN))
        {
            //just put the pStreamEnd pointer afterward
            memcpy(pStreamEnd, p, len);
            pStreamEnd += len;
            LeaveCriticalSection(&g_CriticalSection);
            return len;
        }
        else
        {
            //we need turn the pStreamEnd pointer to the start of gStreamBuffer
            //when the all the buffer are be filled.
            int nLenToTail = 0;
            nLenToTail = gStreamBuffer + STREAM_BUFFER_LEN - pStreamEnd;
            memcpy(pStreamEnd, p, nLenToTail);
            memcpy(gStreamBuffer, p + nLenToTail, len - nLenToTail);
            pStreamEnd = gStreamBuffer + len - nLenToTail - 1;
            LeaveCriticalSection(&g_CriticalSection);
            return len;
        }
    }
    else
    {
        // case the used buffer reach the end and turn around
        if(len > (pStreamBegin - pStreamEnd))
        {
            printf("Input stream is too long 2, pointer = 0x%x, length = %d, buffer available bytes %d \n", p, len, pStreamBegin - pStreamEnd);
            LeaveCriticalSection(&g_CriticalSection);
            return -1;//over flow
        }
        //just copy data to pSteamEnd
        memcpy(pStreamEnd, p, len);
        pStreamEnd += len;
        LeaveCriticalSection(&g_CriticalSection);
        return len;
    }
}

/*
   function: get stream data from gStreamBuffer
*/
int getStreamData(LPBYTE p, DWORD len)
{
    int nBufFilled = 0;
    EnterCriticalSection(&g_CriticalSection);
    if((pStreamEnd < gStreamBuffer)||(pStreamEnd >= gStreamBuffer + STREAM_BUFFER_LEN))
    {
        return -1;//invalid pointer
    }
    if((pStreamBegin < gStreamBuffer)||(pStreamBegin >= gStreamBuffer + STREAM_BUFFER_LEN))
    {
        return -1;//invalid pointer
    }
    if(len < 0)
    {
        return -2;//parameter error
    }
    if(NULL == p)
    {
        return -2;//parameter error
    }

    //get filled byte number in Stream Buffer
    if (pStreamBegin <= pStreamEnd)
    {
        nBufFilled = pStreamEnd - pStreamBegin;
        ASSERT(nBufFilled >= 0);
        //select the buffer length we can send to SDK
        if(len >= nBufFilled)
        {
            memcpy(p, pStreamBegin, nBufFilled);
            pStreamBegin += nBufFilled;
            LeaveCriticalSection(&g_CriticalSection);
            return nBufFilled;
        }
        else
        {
            memcpy(p, pStreamBegin, len);
            pStreamBegin += len;
            LeaveCriticalSection(&g_CriticalSection);
            return len;
        }
    }
    else
    {
        nBufFilled = pStreamEnd + STREAM_BUFFER_LEN - pStreamBegin;
        ASSERT(nBufFilled >= 0);
        //select the buffer length we can send to SDK
        if(len >= nBufFilled)
        {
            //the buffer length is nBufFilled, all filled buffer will be copy to caller
            memcpy(p, pStreamBegin, gStreamBuffer + STREAM_BUFFER_LEN - pStreamBegin);
            memcpy(p+ (STREAM_BUFFER_LEN + gStreamBuffer  - pStreamBegin), gStreamBuffer, nBufFilled - (gStreamBuffer + STREAM_BUFFER_LEN - pStreamBegin));
            pStreamBegin = pStreamEnd;
            LeaveCriticalSection(&g_CriticalSection);
            return nBufFilled;
        }
        else
        {
            if(pStreamBegin + len < gStreamBuffer + STREAM_BUFFER_LEN)    
            {
                //don't need to rotate
                memcpy(p, pStreamBegin, len);
                pStreamBegin += len;
                LeaveCriticalSection(&g_CriticalSection);
                return len;
            }
            else
            {
                //do rotation
                memcpy(p, pStreamBegin, gStreamBuffer + STREAM_BUFFER_LEN - pStreamBegin);
                memcpy(p + (STREAM_BUFFER_LEN + gStreamBuffer - pStreamBegin), gStreamBuffer, len - (gStreamBuffer + STREAM_BUFFER_LEN - pStreamBegin));
                pStreamBegin = len + pStreamBegin - STREAM_BUFFER_LEN;
                LeaveCriticalSection(&g_CriticalSection);
                return len;
            }
        }
    }
    LeaveCriticalSection(&g_CriticalSection);
    return 0;
}