xref: /haiku/src/add-ons/media/plugins/ape_reader/MAClib/APECompress.cpp (revision 053cc0d4fe060114342762e1e8dbbf86a9cad259)
1 #include "All.h"
2 #include "APECompress.h"
3 #include IO_HEADER_FILE
4 #include "APECompressCreate.h"
5 #include "WAVInputSource.h"
6 
CAPECompress()7 CAPECompress::CAPECompress()
8 {
9     m_nBufferHead        = 0;
10     m_nBufferTail        = 0;
11     m_nBufferSize        = 0;
12     m_bBufferLocked        = FALSE;
13     m_bOwnsOutputIO        = FALSE;
14     m_pioOutput            = NULL;
15 
16     m_spAPECompressCreate.Assign(new CAPECompressCreate());
17 
18     m_pBuffer = NULL;
19 }
20 
~CAPECompress()21 CAPECompress::~CAPECompress()
22 {
23     SAFE_ARRAY_DELETE(m_pBuffer)
24 
25     if (m_bOwnsOutputIO)
26     {
27         SAFE_DELETE(m_pioOutput)
28     }
29 }
30 
Start(const char * pOutputFilename,const WAVEFORMATEX * pwfeInput,int nMaxAudioBytes,int nCompressionLevel,const void * pHeaderData,int nHeaderBytes)31 int CAPECompress::Start(const char* pOutputFilename, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
32 {
33     m_pioOutput = new IO_CLASS_NAME;
34     m_bOwnsOutputIO = TRUE;
35 
36     if (m_pioOutput->Create(pOutputFilename) != 0)
37     {
38         return ERROR_INVALID_OUTPUT_FILE;
39     }
40 
41     m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
42         pHeaderData, nHeaderBytes);
43 
44     SAFE_ARRAY_DELETE(m_pBuffer)
45     m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
46     m_pBuffer = new unsigned char [m_nBufferSize];
47     memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
48 
49     return ERROR_SUCCESS;
50 }
51 
StartEx(CIO * pioOutput,const WAVEFORMATEX * pwfeInput,int nMaxAudioBytes,int nCompressionLevel,const void * pHeaderData,int nHeaderBytes)52 int CAPECompress::StartEx(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
53 {
54     m_pioOutput = pioOutput;
55     m_bOwnsOutputIO = FALSE;
56 
57     m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
58         pHeaderData, nHeaderBytes);
59 
60     SAFE_ARRAY_DELETE(m_pBuffer)
61     m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
62     m_pBuffer = new unsigned char [m_nBufferSize];
63     memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
64 
65     return ERROR_SUCCESS;
66 }
67 
GetBufferBytesAvailable()68 int CAPECompress::GetBufferBytesAvailable()
69 {
70     return m_nBufferSize - m_nBufferTail;
71 }
72 
UnlockBuffer(int nBytesAdded,BOOL bProcess)73 int CAPECompress::UnlockBuffer(int nBytesAdded, BOOL bProcess)
74 {
75     if (m_bBufferLocked == FALSE)
76         return ERROR_UNDEFINED;
77 
78     m_nBufferTail += nBytesAdded;
79     m_bBufferLocked = FALSE;
80 
81     if (bProcess)
82     {
83         int nRetVal = ProcessBuffer();
84         if (nRetVal != 0) { return nRetVal; }
85     }
86 
87     return ERROR_SUCCESS;
88 }
89 
LockBuffer(int * pBytesAvailable)90 unsigned char * CAPECompress::LockBuffer(int * pBytesAvailable)
91 {
92     if (m_pBuffer == NULL) { return NULL; }
93 
94     if (m_bBufferLocked)
95         return NULL;
96 
97     m_bBufferLocked = TRUE;
98 
99     if (pBytesAvailable)
100         *pBytesAvailable = GetBufferBytesAvailable();
101 
102     return &m_pBuffer[m_nBufferTail];
103 }
104 
AddData(unsigned char * pData,int nBytes)105 int CAPECompress::AddData(unsigned char * pData, int nBytes)
106 {
107     if (m_pBuffer == NULL) return ERROR_INSUFFICIENT_MEMORY;
108 
109     int nBytesDone = 0;
110 
111     while (nBytesDone < nBytes)
112     {
113         // lock the buffer
114         int nBytesAvailable = 0;
115         unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
116         if (pBuffer == NULL || nBytesAvailable <= 0)
117             return ERROR_UNDEFINED;
118 
119         // calculate how many bytes to copy and add that much to the buffer
120         int nBytesToProcess = min(nBytesAvailable, nBytes - nBytesDone);
121         memcpy(pBuffer, &pData[nBytesDone], nBytesToProcess);
122 
123         // unlock the buffer (fail if not successful)
124         int nRetVal = UnlockBuffer(nBytesToProcess);
125         if (nRetVal != ERROR_SUCCESS)
126                 return nRetVal;
127 
128         // update our progress
129         nBytesDone += nBytesToProcess;
130     }
131 
132     return ERROR_SUCCESS;
133 }
134 
Finish(unsigned char * pTerminatingData,int nTerminatingBytes,int nWAVTerminatingBytes)135 int CAPECompress::Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes)
136 {
137     RETURN_ON_ERROR(ProcessBuffer(TRUE))
138     return m_spAPECompressCreate->Finish(pTerminatingData, nTerminatingBytes, nWAVTerminatingBytes);
139 }
140 
Kill()141 int CAPECompress::Kill()
142 {
143     return ERROR_SUCCESS;
144 }
145 
ProcessBuffer(BOOL bFinalize)146 int CAPECompress::ProcessBuffer(BOOL bFinalize)
147 {
148     if (m_pBuffer == NULL) { return ERROR_UNDEFINED; }
149 
150     try
151     {
152         // process as much as possible
153         int nThreshold = (bFinalize) ? 0 : m_spAPECompressCreate->GetFullFrameBytes();
154 
155         while ((m_nBufferTail - m_nBufferHead) >= nThreshold)
156         {
157             int nFrameBytes = min(m_spAPECompressCreate->GetFullFrameBytes(), m_nBufferTail - m_nBufferHead);
158 
159             if (nFrameBytes == 0)
160                 break;
161 
162             int nRetVal = m_spAPECompressCreate->EncodeFrame(&m_pBuffer[m_nBufferHead], nFrameBytes);
163             if (nRetVal != 0) { return nRetVal; }
164 
165             m_nBufferHead += nFrameBytes;
166         }
167 
168         // shift the buffer
169         if (m_nBufferHead != 0)
170         {
171             int nBytesLeft = m_nBufferTail - m_nBufferHead;
172 
173             if (nBytesLeft != 0)
174                 memmove(m_pBuffer, &m_pBuffer[m_nBufferHead], nBytesLeft);
175 
176             m_nBufferTail -= m_nBufferHead;
177             m_nBufferHead = 0;
178         }
179     }
180     catch(...)
181     {
182         return ERROR_UNDEFINED;
183     }
184 
185     return ERROR_SUCCESS;
186 }
187 
AddDataFromInputSource(CInputSource * pInputSource,int nMaxBytes,int * pBytesAdded)188 int CAPECompress::AddDataFromInputSource(CInputSource * pInputSource, int nMaxBytes, int * pBytesAdded)
189 {
190     // error check the parameters
191     if (pInputSource == NULL) return ERROR_BAD_PARAMETER;
192 
193     // initialize
194     if (pBytesAdded) *pBytesAdded = 0;
195 
196     // lock the buffer
197     int nBytesAvailable = 0;
198     unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
199     if ((pBuffer == NULL) || (nBytesAvailable == 0))
200         return ERROR_INSUFFICIENT_MEMORY;
201 
202     // calculate the 'ideal' number of bytes
203     unsigned int nBytesRead = 0;
204 
205     int nIdealBytes = m_spAPECompressCreate->GetFullFrameBytes() - (m_nBufferTail - m_nBufferHead);
206     if (nIdealBytes > 0)
207     {
208         // get the data
209         int nBytesToAdd = nBytesAvailable;
210 
211         if (nMaxBytes > 0)
212         {
213             if (nBytesToAdd > nMaxBytes) nBytesToAdd = nMaxBytes;
214         }
215 
216         if (nBytesToAdd > nIdealBytes) nBytesToAdd = nIdealBytes;
217 
218         // always make requests along block boundaries
219         while ((nBytesToAdd % m_wfeInput.nBlockAlign) != 0)
220             nBytesToAdd--;
221 
222         int nBlocksToAdd = nBytesToAdd / m_wfeInput.nBlockAlign;
223 
224         // get data
225         int nBlocksAdded = 0;
226         int nRetVal = pInputSource->GetData(pBuffer, nBlocksToAdd, &nBlocksAdded);
227         if (nRetVal != 0)
228             return ERROR_IO_READ;
229         else
230             nBytesRead = (nBlocksAdded * m_wfeInput.nBlockAlign);
231 
232         // store the bytes read
233         if (pBytesAdded)
234             *pBytesAdded = nBytesRead;
235     }
236 
237     // unlock the data and process
238     int nRetVal = UnlockBuffer(nBytesRead, TRUE);
239     if (nRetVal != 0)
240     {
241         return nRetVal;
242     }
243 
244     return ERROR_SUCCESS;
245 }
246 
247