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