⛏️ index : haiku.git

#include "All.h"
#include "APECompress.h"
#include IO_HEADER_FILE
#include "APECompressCreate.h"
#include "WAVInputSource.h"

CAPECompress::CAPECompress()
{
    m_nBufferHead        = 0;
    m_nBufferTail        = 0;
    m_nBufferSize        = 0;
    m_bBufferLocked        = FALSE;
    m_bOwnsOutputIO        = FALSE;
    m_pioOutput            = NULL;

    m_spAPECompressCreate.Assign(new CAPECompressCreate());

    m_pBuffer = NULL;
}

CAPECompress::~CAPECompress()
{
    SAFE_ARRAY_DELETE(m_pBuffer)

    if (m_bOwnsOutputIO)
    {
        SAFE_DELETE(m_pioOutput)
    }
}

int CAPECompress::Start(const char* pOutputFilename, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
{
    m_pioOutput = new IO_CLASS_NAME;
    m_bOwnsOutputIO = TRUE;

    if (m_pioOutput->Create(pOutputFilename) != 0)
    {
        return ERROR_INVALID_OUTPUT_FILE;
    }

    m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
        pHeaderData, nHeaderBytes);

    SAFE_ARRAY_DELETE(m_pBuffer)
    m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
    m_pBuffer = new unsigned char [m_nBufferSize];
    memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));

    return ERROR_SUCCESS;
}

int CAPECompress::StartEx(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
{
    m_pioOutput = pioOutput;
    m_bOwnsOutputIO = FALSE;

    m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
        pHeaderData, nHeaderBytes);

    SAFE_ARRAY_DELETE(m_pBuffer)
    m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
    m_pBuffer = new unsigned char [m_nBufferSize];
    memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));

    return ERROR_SUCCESS;
}

int CAPECompress::GetBufferBytesAvailable()
{
    return m_nBufferSize - m_nBufferTail;
}

int CAPECompress::UnlockBuffer(int nBytesAdded, BOOL bProcess)
{
    if (m_bBufferLocked == FALSE)
        return ERROR_UNDEFINED;

    m_nBufferTail += nBytesAdded;
    m_bBufferLocked = FALSE;

    if (bProcess)
    {
        int nRetVal = ProcessBuffer();
        if (nRetVal != 0) { return nRetVal; }
    }

    return ERROR_SUCCESS;
}

unsigned char * CAPECompress::LockBuffer(int * pBytesAvailable)
{
    if (m_pBuffer == NULL) { return NULL; }

    if (m_bBufferLocked)
        return NULL;

    m_bBufferLocked = TRUE;

    if (pBytesAvailable)
        *pBytesAvailable = GetBufferBytesAvailable();

    return &m_pBuffer[m_nBufferTail];
}

int CAPECompress::AddData(unsigned char * pData, int nBytes)
{
    if (m_pBuffer == NULL) return ERROR_INSUFFICIENT_MEMORY;

    int nBytesDone = 0;

    while (nBytesDone < nBytes)
    {
        // lock the buffer
        int nBytesAvailable = 0;
        unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
        if (pBuffer == NULL || nBytesAvailable <= 0)
            return ERROR_UNDEFINED;

        // calculate how many bytes to copy and add that much to the buffer
        int nBytesToProcess = min(nBytesAvailable, nBytes - nBytesDone);
        memcpy(pBuffer, &pData[nBytesDone], nBytesToProcess);

        // unlock the buffer (fail if not successful)
        int nRetVal = UnlockBuffer(nBytesToProcess);
        if (nRetVal != ERROR_SUCCESS)
                return nRetVal;

        // update our progress
        nBytesDone += nBytesToProcess;
    }

    return ERROR_SUCCESS;
}

int CAPECompress::Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes)
{
    RETURN_ON_ERROR(ProcessBuffer(TRUE))
    return m_spAPECompressCreate->Finish(pTerminatingData, nTerminatingBytes, nWAVTerminatingBytes);
}

int CAPECompress::Kill()
{
    return ERROR_SUCCESS;
}

int CAPECompress::ProcessBuffer(BOOL bFinalize)
{
    if (m_pBuffer == NULL) { return ERROR_UNDEFINED; }

    try
    {
        // process as much as possible
        int nThreshold = (bFinalize) ? 0 : m_spAPECompressCreate->GetFullFrameBytes();

        while ((m_nBufferTail - m_nBufferHead) >= nThreshold)
        {
            int nFrameBytes = min(m_spAPECompressCreate->GetFullFrameBytes(), m_nBufferTail - m_nBufferHead);

            if (nFrameBytes == 0)
                break;

            int nRetVal = m_spAPECompressCreate->EncodeFrame(&m_pBuffer[m_nBufferHead], nFrameBytes);
            if (nRetVal != 0) { return nRetVal; }

            m_nBufferHead += nFrameBytes;
        }

        // shift the buffer
        if (m_nBufferHead != 0)
        {
            int nBytesLeft = m_nBufferTail - m_nBufferHead;

            if (nBytesLeft != 0)
                memmove(m_pBuffer, &m_pBuffer[m_nBufferHead], nBytesLeft);

            m_nBufferTail -= m_nBufferHead;
            m_nBufferHead = 0;
        }
    }
    catch(...)
    {
        return ERROR_UNDEFINED;
    }

    return ERROR_SUCCESS;
}

int CAPECompress::AddDataFromInputSource(CInputSource * pInputSource, int nMaxBytes, int * pBytesAdded)
{
    // error check the parameters
    if (pInputSource == NULL) return ERROR_BAD_PARAMETER;

    // initialize
    if (pBytesAdded) *pBytesAdded = 0;

    // lock the buffer
    int nBytesAvailable = 0;
    unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
    if ((pBuffer == NULL) || (nBytesAvailable == 0))
        return ERROR_INSUFFICIENT_MEMORY;

    // calculate the 'ideal' number of bytes
    unsigned int nBytesRead = 0;

    int nIdealBytes = m_spAPECompressCreate->GetFullFrameBytes() - (m_nBufferTail - m_nBufferHead);
    if (nIdealBytes > 0)
    {
        // get the data
        int nBytesToAdd = nBytesAvailable;

        if (nMaxBytes > 0)
        {
            if (nBytesToAdd > nMaxBytes) nBytesToAdd = nMaxBytes;
        }

        if (nBytesToAdd > nIdealBytes) nBytesToAdd = nIdealBytes;

        // always make requests along block boundaries
        while ((nBytesToAdd % m_wfeInput.nBlockAlign) != 0)
            nBytesToAdd--;

        int nBlocksToAdd = nBytesToAdd / m_wfeInput.nBlockAlign;

        // get data
        int nBlocksAdded = 0;
        int nRetVal = pInputSource->GetData(pBuffer, nBlocksToAdd, &nBlocksAdded);
        if (nRetVal != 0)
            return ERROR_IO_READ;
        else
            nBytesRead = (nBlocksAdded * m_wfeInput.nBlockAlign);

        // store the bytes read
        if (pBytesAdded)
            *pBytesAdded = nBytesRead;
    }

    // unlock the data and process
    int nRetVal = UnlockBuffer(nBytesRead, TRUE);
    if (nRetVal != 0)
    {
        return nRetVal;
    }

    return ERROR_SUCCESS;
}