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