xref: /haiku/src/add-ons/media/plugins/ape_reader/MAClib/APEDecompress.cpp (revision 053cc0d4fe060114342762e1e8dbbf86a9cad259)
1 #include <algorithm>
2 
3 #include "All.h"
4 #include "APEDecompress.h"
5 #include "APEInfo.h"
6 #include "Prepare.h"
7 #include "UnBitArray.h"
8 #include "NewPredictor.h"
9 
10 #define DECODE_BLOCK_SIZE        4096
11 
CAPEDecompress(int * pErrorCode,CAPEInfo * pAPEInfo,int nStartBlock,int nFinishBlock)12 CAPEDecompress::CAPEDecompress(int * pErrorCode, CAPEInfo * pAPEInfo, int nStartBlock, int nFinishBlock)
13 {
14     *pErrorCode = ERROR_SUCCESS;
15 
16     // open / analyze the file
17     m_spAPEInfo.Assign(pAPEInfo);
18 
19     // version check (this implementation only works with 3.93 and later files)
20     if (GetInfo(APE_INFO_FILE_VERSION) < 3930)
21     {
22         *pErrorCode = ERROR_UNDEFINED;
23         return;
24     }
25 
26     // get format information
27     GetInfo(APE_INFO_WAVEFORMATEX, (int) &m_wfeInput);
28     m_nBlockAlign = GetInfo(APE_INFO_BLOCK_ALIGN);
29 
30     // initialize other stuff
31     m_bDecompressorInitialized = FALSE;
32     m_nCurrentFrame = 0;
33     m_nCurrentBlock = 0;
34     m_nCurrentFrameBufferBlock = 0;
35     m_nFrameBufferFinishedBlocks = 0;
36     m_bErrorDecodingCurrentFrame = FALSE;
37 
38     // set the "real" start and finish blocks
39     m_nStartBlock = (nStartBlock < 0)
40 		? 0 : min(nStartBlock, GetInfo(APE_INFO_TOTAL_BLOCKS));
41     m_nFinishBlock = (nFinishBlock < 0)
42 		? GetInfo(APE_INFO_TOTAL_BLOCKS)
43 		: min(nFinishBlock, GetInfo(APE_INFO_TOTAL_BLOCKS));
44     m_bIsRanged = (m_nStartBlock != 0) || (m_nFinishBlock != GetInfo(APE_INFO_TOTAL_BLOCKS));
45 }
46 
~CAPEDecompress()47 CAPEDecompress::~CAPEDecompress()
48 {
49 
50 }
51 
InitializeDecompressor()52 int CAPEDecompress::InitializeDecompressor()
53 {
54     // check if we have anything to do
55     if (m_bDecompressorInitialized)
56         return ERROR_SUCCESS;
57 
58     // update the initialized flag
59     m_bDecompressorInitialized = TRUE;
60 
61     // create a frame buffer
62     m_cbFrameBuffer.CreateBuffer((GetInfo(APE_INFO_BLOCKS_PER_FRAME) + DECODE_BLOCK_SIZE) * m_nBlockAlign, m_nBlockAlign * 64);
63 
64     // create decoding components
65     m_spUnBitArray.Assign((CUnBitArrayBase *) CreateUnBitArray(this, GetInfo(APE_INFO_FILE_VERSION)));
66 
67     if (GetInfo(APE_INFO_FILE_VERSION) >= 3950)
68     {
69         m_spNewPredictorX.Assign(new CPredictorDecompress3950toCurrent(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
70         m_spNewPredictorY.Assign(new CPredictorDecompress3950toCurrent(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
71     }
72     else
73     {
74         m_spNewPredictorX.Assign(new CPredictorDecompressNormal3930to3950(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
75         m_spNewPredictorY.Assign(new CPredictorDecompressNormal3930to3950(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
76     }
77 
78     // seek to the beginning
79     return Seek(0);
80 }
81 
GetData(char * pBuffer,int nBlocks,int * pBlocksRetrieved)82 int CAPEDecompress::GetData(char * pBuffer, int nBlocks, int * pBlocksRetrieved)
83 {
84     int nRetVal = ERROR_SUCCESS;
85     if (pBlocksRetrieved) *pBlocksRetrieved = 0;
86 
87     // make sure we're initialized
88     RETURN_ON_ERROR(InitializeDecompressor())
89 
90     // cap
91     int nBlocksUntilFinish = m_nFinishBlock - m_nCurrentBlock;
92     const int nBlocksToRetrieve = min(nBlocks, nBlocksUntilFinish);
93 
94     // get the data
95     unsigned char * pOutputBuffer = (unsigned char *) pBuffer;
96     int nBlocksLeft = nBlocksToRetrieve; int nBlocksThisPass = 1;
97     while ((nBlocksLeft > 0) && (nBlocksThisPass > 0))
98     {
99         // fill up the frame buffer
100         int nDecodeRetVal = FillFrameBuffer();
101         if (nDecodeRetVal != ERROR_SUCCESS)
102             nRetVal = nDecodeRetVal;
103 
104         // analyze how much to remove from the buffer
105         const int nFrameBufferBlocks = m_nFrameBufferFinishedBlocks;
106         nBlocksThisPass = min(nBlocksLeft, nFrameBufferBlocks);
107 
108         // remove as much as possible
109         if (nBlocksThisPass > 0)
110         {
111             m_cbFrameBuffer.Get(pOutputBuffer, nBlocksThisPass * m_nBlockAlign);
112             pOutputBuffer += nBlocksThisPass * m_nBlockAlign;
113             nBlocksLeft -= nBlocksThisPass;
114             m_nFrameBufferFinishedBlocks -= nBlocksThisPass;
115         }
116     }
117 
118     // calculate the blocks retrieved
119     int nBlocksRetrieved = nBlocksToRetrieve - nBlocksLeft;
120 
121     // update position
122     m_nCurrentBlock += nBlocksRetrieved;
123     if (pBlocksRetrieved) *pBlocksRetrieved = nBlocksRetrieved;
124 
125     return nRetVal;
126 }
127 
Seek(int nBlockOffset)128 int CAPEDecompress::Seek(int nBlockOffset)
129 {
130     RETURN_ON_ERROR(InitializeDecompressor())
131 
132     // use the offset
133     nBlockOffset += m_nStartBlock;
134 
135     // cap (to prevent seeking too far)
136     if (nBlockOffset >= m_nFinishBlock)
137         nBlockOffset = m_nFinishBlock - 1;
138     if (nBlockOffset < m_nStartBlock)
139         nBlockOffset = m_nStartBlock;
140 
141     // seek to the perfect location
142     int nBaseFrame = nBlockOffset / GetInfo(APE_INFO_BLOCKS_PER_FRAME);
143     int nBlocksToSkip = nBlockOffset % GetInfo(APE_INFO_BLOCKS_PER_FRAME);
144     int nBytesToSkip = nBlocksToSkip * m_nBlockAlign;
145 
146     m_nCurrentBlock = nBaseFrame * GetInfo(APE_INFO_BLOCKS_PER_FRAME);
147     m_nCurrentFrameBufferBlock = nBaseFrame * GetInfo(APE_INFO_BLOCKS_PER_FRAME);
148     m_nCurrentFrame = nBaseFrame;
149     m_nFrameBufferFinishedBlocks = 0;
150     m_cbFrameBuffer.Empty();
151     RETURN_ON_ERROR(SeekToFrame(m_nCurrentFrame));
152 
153     // skip necessary blocks
154     CSmartPtr<char> spTempBuffer(new char [nBytesToSkip], TRUE);
155     if (spTempBuffer == NULL) return ERROR_INSUFFICIENT_MEMORY;
156 
157     int nBlocksRetrieved = 0;
158     GetData(spTempBuffer, nBlocksToSkip, &nBlocksRetrieved);
159     if (nBlocksRetrieved != nBlocksToSkip)
160         return ERROR_UNDEFINED;
161 
162     return ERROR_SUCCESS;
163 }
164 
165 /*****************************************************************************************
166 Decodes blocks of data
167 *****************************************************************************************/
FillFrameBuffer()168 int CAPEDecompress::FillFrameBuffer()
169 {
170     int nRetVal = ERROR_SUCCESS;
171 
172      // determine the maximum blocks we can decode
173     // note that we won't do end capping because we can't use data
174     // until EndFrame(...) successfully handles the frame
175     // that means we may decode a little extra in end capping cases
176     // but this allows robust error handling of bad frames
177     int nMaxBlocks = m_cbFrameBuffer.MaxAdd() / m_nBlockAlign;
178 
179     // loop and decode data
180     int nBlocksLeft = nMaxBlocks;
181     while (nBlocksLeft > 0)
182     {
183         int nFrameBlocks = GetInfo(APE_INFO_FRAME_BLOCKS, m_nCurrentFrame);
184         if (nFrameBlocks < 0)
185             break;
186 
187         int nFrameOffsetBlocks = m_nCurrentFrameBufferBlock % GetInfo(APE_INFO_BLOCKS_PER_FRAME);
188         int nFrameBlocksLeft = nFrameBlocks - nFrameOffsetBlocks;
189         int nBlocksThisPass = min(nFrameBlocksLeft, nBlocksLeft);
190 
191         // start the frame if we need to
192         if (nFrameOffsetBlocks == 0)
193             StartFrame();
194 
195         // store the frame buffer bytes before we start
196         int nFrameBufferBytes = m_cbFrameBuffer.MaxGet();
197 
198         // decode data
199         DecodeBlocksToFrameBuffer(nBlocksThisPass);
200 
201         // end the frame if we need to
202         if ((nFrameOffsetBlocks + nBlocksThisPass) >= nFrameBlocks)
203         {
204             EndFrame();
205             if (m_bErrorDecodingCurrentFrame)
206             {
207                 // remove any decoded data from the buffer
208                 m_cbFrameBuffer.RemoveTail(m_cbFrameBuffer.MaxGet() - nFrameBufferBytes);
209 
210                 // add silence
211                 unsigned char cSilence = (GetInfo(APE_INFO_BITS_PER_SAMPLE) == 8) ? 127 : 0;
212                 for (int z = 0; z < nFrameBlocks * m_nBlockAlign; z++)
213                 {
214                     *m_cbFrameBuffer.GetDirectWritePointer() = cSilence;
215                     m_cbFrameBuffer.UpdateAfterDirectWrite(1);
216                 }
217 
218                 // seek to try to synchronize after an error
219                 SeekToFrame(m_nCurrentFrame);
220 
221                 // save the return value
222                 nRetVal = ERROR_INVALID_CHECKSUM;
223             }
224         }
225 
226         nBlocksLeft -= nBlocksThisPass;
227     }
228 
229     return nRetVal;
230 }
231 
DecodeBlocksToFrameBuffer(int nBlocks)232 void CAPEDecompress::DecodeBlocksToFrameBuffer(int nBlocks)
233 {
234     // decode the samples
235     int nBlocksProcessed = 0;
236 
237     try
238     {
239         if (m_wfeInput.nChannels == 2)
240         {
241             if ((m_nSpecialCodes & SPECIAL_FRAME_LEFT_SILENCE) &&
242                 (m_nSpecialCodes & SPECIAL_FRAME_RIGHT_SILENCE))
243             {
244                 for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
245                 {
246                     m_Prepare.Unprepare(0, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
247                     m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
248                 }
249             }
250             else if (m_nSpecialCodes & SPECIAL_FRAME_PSEUDO_STEREO)
251             {
252                 for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
253                 {
254                     int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
255                     m_Prepare.Unprepare(X, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
256                     m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
257                 }
258             }
259             else
260             {
261                 if (m_spAPEInfo->GetInfo(APE_INFO_FILE_VERSION) >= 3950)
262                 {
263                     for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
264                     {
265                         int nY = m_spUnBitArray->DecodeValueRange(m_BitArrayStateY);
266                         int nX = m_spUnBitArray->DecodeValueRange(m_BitArrayStateX);
267                         int Y = m_spNewPredictorY->DecompressValue(nY, m_nLastX);
268                         int X = m_spNewPredictorX->DecompressValue(nX, Y);
269                         m_nLastX = X;
270 
271                         m_Prepare.Unprepare(X, Y, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
272                         m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
273                     }
274                 }
275                 else
276                 {
277                     for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
278                     {
279                         int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
280                         int Y = m_spNewPredictorY->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateY));
281 
282                         m_Prepare.Unprepare(X, Y, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
283                         m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
284                     }
285                 }
286             }
287         }
288         else
289         {
290             if (m_nSpecialCodes & SPECIAL_FRAME_MONO_SILENCE)
291             {
292                 for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
293                 {
294                     m_Prepare.Unprepare(0, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
295                     m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
296                 }
297             }
298             else
299             {
300                 for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
301                 {
302                     int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
303                     m_Prepare.Unprepare(X, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
304                     m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
305                 }
306             }
307         }
308     }
309     catch(...)
310     {
311         m_bErrorDecodingCurrentFrame = TRUE;
312     }
313 
314     m_nCurrentFrameBufferBlock += nBlocks;
315 }
316 
StartFrame()317 void CAPEDecompress::StartFrame()
318 {
319     m_nCRC = 0xFFFFFFFF;
320 
321     // get the frame header
322     m_nStoredCRC = m_spUnBitArray->DecodeValue(DECODE_VALUE_METHOD_UNSIGNED_INT);
323     m_bErrorDecodingCurrentFrame = FALSE;
324 
325     // get any 'special' codes if the file uses them (for silence, FALSE stereo, etc.)
326     m_nSpecialCodes = 0;
327     if (GET_USES_SPECIAL_FRAMES(m_spAPEInfo))
328     {
329         if (m_nStoredCRC & 0x80000000)
330         {
331             m_nSpecialCodes = m_spUnBitArray->DecodeValue(DECODE_VALUE_METHOD_UNSIGNED_INT);
332         }
333         m_nStoredCRC &= 0x7FFFFFFF;
334     }
335 
336     m_spNewPredictorX->Flush();
337     m_spNewPredictorY->Flush();
338 
339     m_spUnBitArray->FlushState(m_BitArrayStateX);
340     m_spUnBitArray->FlushState(m_BitArrayStateY);
341 
342     m_spUnBitArray->FlushBitArray();
343 
344     m_nLastX = 0;
345 }
346 
EndFrame()347 void CAPEDecompress::EndFrame()
348 {
349     m_nFrameBufferFinishedBlocks += GetInfo(APE_INFO_FRAME_BLOCKS, m_nCurrentFrame);
350     m_nCurrentFrame++;
351 
352     // finalize
353     m_spUnBitArray->Finalize();
354 
355     // check the CRC
356     m_nCRC = m_nCRC ^ 0xFFFFFFFF;
357     m_nCRC >>= 1;
358     if (m_nCRC != m_nStoredCRC)
359         m_bErrorDecodingCurrentFrame = TRUE;
360 }
361 
362 /*****************************************************************************************
363 Seek to the proper frame (if necessary) and do any alignment of the bit array
364 *****************************************************************************************/
SeekToFrame(int nFrameIndex)365 int CAPEDecompress::SeekToFrame(int nFrameIndex)
366 {
367     int nSeekRemainder = (GetInfo(APE_INFO_SEEK_BYTE, nFrameIndex) - GetInfo(APE_INFO_SEEK_BYTE, 0)) % 4;
368     return m_spUnBitArray->FillAndResetBitArray(GetInfo(APE_INFO_SEEK_BYTE, nFrameIndex) - nSeekRemainder, nSeekRemainder * 8);
369 }
370 
371 /*****************************************************************************************
372 Get information from the decompressor
373 *****************************************************************************************/
GetInfo(APE_DECOMPRESS_FIELDS Field,int nParam1,int nParam2)374 int CAPEDecompress::GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1, int nParam2)
375 {
376     int nRetVal = 0;
377     BOOL bHandled = TRUE;
378 
379     switch (Field)
380     {
381     case APE_DECOMPRESS_CURRENT_BLOCK:
382         nRetVal = m_nCurrentBlock - m_nStartBlock;
383         break;
384     case APE_DECOMPRESS_CURRENT_MS:
385     {
386         int nSampleRate = m_spAPEInfo->GetInfo(APE_INFO_SAMPLE_RATE, 0, 0);
387         if (nSampleRate > 0)
388             nRetVal = int((double(m_nCurrentBlock) * double(1000)) / double(nSampleRate));
389         break;
390     }
391     case APE_DECOMPRESS_TOTAL_BLOCKS:
392         nRetVal = m_nFinishBlock - m_nStartBlock;
393         break;
394     case APE_DECOMPRESS_LENGTH_MS:
395     {
396         int nSampleRate = m_spAPEInfo->GetInfo(APE_INFO_SAMPLE_RATE, 0, 0);
397         if (nSampleRate > 0)
398             nRetVal = int((double(m_nFinishBlock - m_nStartBlock) * double(1000)) / double(nSampleRate));
399         break;
400     }
401     case APE_DECOMPRESS_CURRENT_BITRATE:
402         nRetVal = GetInfo(APE_INFO_FRAME_BITRATE, m_nCurrentFrame);
403         break;
404     case APE_DECOMPRESS_AVERAGE_BITRATE:
405     {
406         if (m_bIsRanged)
407         {
408             // figure the frame range
409             const int nBlocksPerFrame = GetInfo(APE_INFO_BLOCKS_PER_FRAME);
410             int nStartFrame = m_nStartBlock / nBlocksPerFrame;
411             int nFinishFrame = (m_nFinishBlock + nBlocksPerFrame - 1) / nBlocksPerFrame;
412 
413             // get the number of bytes in the first and last frame
414             int nTotalBytes = (GetInfo(APE_INFO_FRAME_BYTES, nStartFrame) * (m_nStartBlock % nBlocksPerFrame)) / nBlocksPerFrame;
415             if (nFinishFrame != nStartFrame)
416                 nTotalBytes += (GetInfo(APE_INFO_FRAME_BYTES, nFinishFrame) * (m_nFinishBlock % nBlocksPerFrame)) / nBlocksPerFrame;
417 
418             // get the number of bytes in between
419             const int nTotalFrames = GetInfo(APE_INFO_TOTAL_FRAMES);
420             for (int nFrame = nStartFrame + 1; (nFrame < nFinishFrame) && (nFrame < nTotalFrames); nFrame++)
421                 nTotalBytes += GetInfo(APE_INFO_FRAME_BYTES, nFrame);
422 
423             // figure the bitrate
424             int nTotalMS = int((double(m_nFinishBlock - m_nStartBlock) * double(1000)) / double(GetInfo(APE_INFO_SAMPLE_RATE)));
425             if (nTotalMS != 0)
426                 nRetVal = (nTotalBytes * 8) / nTotalMS;
427         }
428         else
429         {
430             nRetVal = GetInfo(APE_INFO_AVERAGE_BITRATE);
431         }
432 
433         break;
434     }
435     default:
436         bHandled = FALSE;
437     }
438 
439     if (!bHandled && m_bIsRanged)
440     {
441         bHandled = TRUE;
442 
443         switch (Field)
444         {
445         case APE_INFO_WAV_HEADER_BYTES:
446             nRetVal = sizeof(WAVE_HEADER);
447             break;
448         case APE_INFO_WAV_HEADER_DATA:
449         {
450             char * pBuffer = (char *) nParam1;
451             int nMaxBytes = nParam2;
452 
453             if (sizeof(WAVE_HEADER) > static_cast<uint32>(nMaxBytes))
454             {
455                 nRetVal = -1;
456             }
457             else
458             {
459                 WAVEFORMATEX wfeFormat; GetInfo(APE_INFO_WAVEFORMATEX, (int) &wfeFormat, 0);
460                 WAVE_HEADER WAVHeader; FillWaveHeader(&WAVHeader,
461                     (m_nFinishBlock - m_nStartBlock) * GetInfo(APE_INFO_BLOCK_ALIGN),
462                     &wfeFormat,    0);
463                 memcpy(pBuffer, &WAVHeader, sizeof(WAVE_HEADER));
464                 nRetVal = 0;
465             }
466             break;
467         }
468         case APE_INFO_WAV_TERMINATING_BYTES:
469             nRetVal = 0;
470             break;
471         case APE_INFO_WAV_TERMINATING_DATA:
472             nRetVal = 0;
473             break;
474         default:
475             bHandled = FALSE;
476         }
477     }
478 
479     if (bHandled == FALSE)
480         nRetVal = m_spAPEInfo->GetInfo(Field, nParam1, nParam2);
481 
482     return nRetVal;
483 }
484