root/trunk/ACPublic/ACSimpleCodec.cpp

Revision 219, 12.0 kB (checked in by dconrad, 2 years ago)

WMA v1 and v2 decoder. Tested with samples in AVI. Refs #38

Line 
1 /*      Copyright:      © Copyright 2005 Apple Computer, Inc. All rights reserved.
2
3         Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
4                         ("Apple") in consideration of your agreement to the following terms, and your
5                         use, installation, modification or redistribution of this Apple software
6                         constitutes acceptance of these terms.  If you do not agree with these terms,
7                         please do not use, install, modify or redistribute this Apple software.
8
9                         In consideration of your agreement to abide by the following terms, and subject
10                         to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
11                         copyrights in this original Apple software (the "Apple Software"), to use,
12                         reproduce, modify and redistribute the Apple Software, with or without
13                         modifications, in source and/or binary forms; provided that if you redistribute
14                         the Apple Software in its entirety and without modifications, you must retain
15                         this notice and the following text and disclaimers in all such redistributions of
16                         the Apple Software.  Neither the name, trademarks, service marks or logos of
17                         Apple Computer, Inc. may be used to endorse or promote products derived from the
18                         Apple Software without specific prior written permission from Apple.  Except as
19                         expressly stated in this notice, no other rights or licenses, express or implied,
20                         are granted by Apple herein, including but not limited to any patent rights that
21                         may be infringed by your derivative works or by other works in which the Apple
22                         Software may be incorporated.
23
24                         The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
25                         WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
26                         WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27                         PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
28                         COMBINATION WITH YOUR PRODUCTS.
29
30                         IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
31                         CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
32                         GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33                         ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
34                         OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
35                         (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
36                         ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38 /*=============================================================================
39         ACSimpleCodec.cpp
40
41 =============================================================================*/
42
43 //=============================================================================
44 //      Includes
45 //=============================================================================
46
47 #include "ACSimpleCodec.h"
48 #include <string.h>
49
50 //=============================================================================
51 //      ACSimpleCodec
52 //=============================================================================
53
54 static const UInt32 kBufferPad = 64; // this is used to prevent end from passing start.
55
56 ACSimpleCodec::ACSimpleCodec(UInt32 inInputBufferByteSize)
57 :
58         ACBaseCodec(),
59         mInputBuffer(NULL),
60         mInputBufferByteSize(inInputBufferByteSize+kBufferPad),
61         mInputBufferStart(0),
62         mInputBufferEnd(0)
63 {
64 }
65
66 ACSimpleCodec::~ACSimpleCodec()
67 {
68         delete[] mInputBuffer;
69 }
70
71 void    ACSimpleCodec::Initialize(const AudioStreamBasicDescription* inInputFormat, const AudioStreamBasicDescription* inOutputFormat, const void* inMagicCookie, UInt32 inMagicCookieByteSize)
72 {
73         ReallocateInputBuffer(mInputBufferByteSize - kBufferPad);
74        
75         ACBaseCodec::Initialize(inInputFormat, inOutputFormat, inMagicCookie, inMagicCookieByteSize);
76 }
77
78 void    ACSimpleCodec::Uninitialize()
79 {
80         //      get rid of the buffer
81         delete[] mInputBuffer;
82         mInputBuffer = NULL;
83        
84         //      reset the ring buffer state
85         mInputBufferStart = 0;
86         mInputBufferEnd = 0;
87        
88         ACBaseCodec::Uninitialize();
89 }
90
91 void    ACSimpleCodec::Reset()
92 {
93         //      clear the entire input buffer
94         if (mInputBuffer) { // could be called before allocated.
95                 memset(mInputBuffer, 0, mInputBufferByteSize);
96         }
97        
98         //      reset the ring buffer state
99         mInputBufferStart = 0;
100         mInputBufferEnd = 0;
101        
102         ACBaseCodec::Reset();
103 }
104
105 UInt32  ACSimpleCodec::GetInputBufferByteSize() const
106 {
107         return mInputBufferByteSize - kBufferPad; // minus kBufferPad to prevent end moving past start
108 }
109
110 UInt32  ACSimpleCodec::GetUsedInputBufferByteSize() const
111 {
112         UInt32 theAnswer = 0;
113        
114         //      this object uses a ring buffer
115         if(mInputBufferStart <= mInputBufferEnd)
116         {
117                 //      the active region is contiguous
118                 theAnswer = mInputBufferEnd - mInputBufferStart;
119         }
120         else
121         {
122                 //      the active region wraps around
123                 theAnswer = (mInputBufferByteSize - mInputBufferStart) + mInputBufferEnd;
124         }
125        
126         return theAnswer;
127 }
128
129
130 void    ACSimpleCodec::AppendInputData(const void* inInputData, UInt32& ioInputDataByteSize, UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription)
131 {
132         //      this buffer handling code doesn't care about such things as the packet descriptions
133         if(!mIsInitialized) CODEC_THROW(kAudioCodecStateError);
134        
135         //      this is a ring buffer we're dealing with, so we need to set up a few things
136         UInt32 theUsedByteSize = GetUsedInputBufferByteSize();
137         UInt32 theAvailableByteSize = GetInputBufferByteSize() - theUsedByteSize;
138
139         UInt32 theMaxAvailableInputBytes = ioInputDataByteSize; // we can't consume more than we get
140
141         const Byte* theInputData = static_cast<const Byte*>(inInputData);
142        
143         // >>jamesmcc: added this because ioNumberPackets was not being updated if less was taken than given.
144         // THIS ASSUMES CBR!
145         UInt32 bytesPerPacketOfInput = mInputFormat.mBytesPerPacket;
146         UInt32 theAvailablePacketSize = theAvailableByteSize / bytesPerPacketOfInput;
147        
148         UInt32 minPacketSize = ioNumberPackets < theAvailablePacketSize ? ioNumberPackets : theAvailablePacketSize;
149         UInt32 minByteSize = minPacketSize * bytesPerPacketOfInput;
150        
151         //      we can copy only as much data as there is or up to how much space is availiable
152         ioNumberPackets = minPacketSize;
153         ioInputDataByteSize = minByteSize;
154        
155         // ioInputDataByteSize had better be <= to theMaxAvailableInputBytes or we're screwed
156         if (ioInputDataByteSize > theMaxAvailableInputBytes)
157         {
158                 CODEC_THROW(kAudioCodecStateError);
159         }
160         // <<jamesmcc
161        
162         //      now we have to copy the data taking into account the wrap around and where the start is
163         if(mInputBufferEnd + ioInputDataByteSize < mInputBufferByteSize)
164         {
165                 //      no wrap around here
166                 memcpy(mInputBuffer + mInputBufferEnd, theInputData, ioInputDataByteSize);
167                
168                 //      adjust the end point
169                 mInputBufferEnd += ioInputDataByteSize;
170         }
171         else
172         {
173                 //      the copy will wrap
174                
175                 //      copy the first part
176                 UInt32 theBeforeWrapByteSize = mInputBufferByteSize - mInputBufferEnd;
177                 memcpy(mInputBuffer + mInputBufferEnd, theInputData, theBeforeWrapByteSize);
178                
179                 //      and the rest
180                 UInt32 theAfterWrapByteSize = ioInputDataByteSize - theBeforeWrapByteSize;
181                 memcpy(mInputBuffer, theInputData + theBeforeWrapByteSize, theAfterWrapByteSize);
182                
183                 //      adjust the end point
184                 mInputBufferEnd = theAfterWrapByteSize;
185         }
186        
187 }
188
189
190 void    ACSimpleCodec::ZeroPadInputData(UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription)
191 {
192         //      this buffer handling code doesn't care about such things as the packet descriptions
193         if(!mIsInitialized) CODEC_THROW(kAudioCodecStateError);
194        
195        
196         //      this is a ring buffer we're dealing with, so we need to set up a few things
197         UInt32 theUsedByteSize = GetUsedInputBufferByteSize();
198         UInt32 theAvailableByteSize = GetInputBufferByteSize() - theUsedByteSize;
199        
200         // >>jamesmcc: added this because ioNumberPackets was not being updated if less was taken than given.
201         // THIS ASSUMES CBR!
202         UInt32 bytesPerPacketOfInput = mInputFormat.mBytesPerPacket;
203         UInt32 theAvailablePacketSize = theAvailableByteSize / bytesPerPacketOfInput;
204        
205         UInt32 minPacketSize = ioNumberPackets < theAvailablePacketSize ? ioNumberPackets : theAvailablePacketSize;
206         UInt32 minByteSize = minPacketSize * bytesPerPacketOfInput;
207        
208         //      we can copy only as much data as there is or up to how much space is availiable
209         ioNumberPackets = minPacketSize;
210        
211         // <<jamesmcc
212        
213         //      now we have to copy the data taking into account the wrap around and where the start is
214         if(mInputBufferEnd + minByteSize < mInputBufferByteSize)
215         {
216                 //      no wrap around here
217                 memset(mInputBuffer + mInputBufferEnd, 0, minByteSize);
218                
219                 //      adjust the end point
220                 mInputBufferEnd += minByteSize;
221         }
222         else
223         {
224                 //      the copy will wrap
225                
226                 //      copy the first part
227                 UInt32 theBeforeWrapByteSize = mInputBufferByteSize - mInputBufferEnd;
228                 memset(mInputBuffer + mInputBufferEnd, 0, theBeforeWrapByteSize);
229                
230                 //      and the rest
231                 UInt32 theAfterWrapByteSize = minByteSize - theBeforeWrapByteSize;
232                 memset(mInputBuffer, 0, theAfterWrapByteSize);
233                
234                 //      adjust the end point
235                 mInputBufferEnd = theAfterWrapByteSize;
236         }
237 }
238
239
240 void    ACSimpleCodec::ConsumeInputData(UInt32 inConsumedByteSize)
241 {
242         //      this is a convenience routine to make maintaining the ring buffer state easy
243         UInt32 theContiguousRange = GetInputBufferContiguousByteSize();
244        
245         if(inConsumedByteSize > GetUsedInputBufferByteSize()) CODEC_THROW(kAudioCodecUnspecifiedError);
246        
247         if(inConsumedByteSize <= theContiguousRange)
248         {
249                 //      the region to consume doesn't wrap
250                
251                 //      figure out how much to consume
252                 inConsumedByteSize = (theContiguousRange < inConsumedByteSize) ? theContiguousRange : inConsumedByteSize;
253                
254                 //      clear the consumed bits
255                 memset(mInputBuffer + mInputBufferStart, 0, inConsumedByteSize);
256                
257                 //      adjust the start
258                 mInputBufferStart += inConsumedByteSize;
259         }
260         else
261         {
262                 //      the region to consume will wrap
263                
264                 //      clear the bits to the end of the buffer
265                 memset(mInputBuffer + mInputBufferStart, 0, theContiguousRange);
266                
267                 //      now clear the bits left from the start
268                 memset(mInputBuffer, 0, inConsumedByteSize - theContiguousRange);
269                
270                 //      adjust the start
271                 mInputBufferStart = inConsumedByteSize - theContiguousRange;
272         }
273 }
274
275
276 Byte* ACSimpleCodec::GetBytes(UInt32& ioNumberBytes) const
277 {
278         // if a client's algorithm has to have contiguous data and mInputBuffer wraps, then someone has to make a copy.
279         // I can do it more efficiently than the client.
280        
281         if(!mIsInitialized) CODEC_THROW(kAudioCodecStateError);
282
283         UInt32 theUsedByteSize = GetUsedInputBufferByteSize();
284         //UInt32 theAvailableByteSize = GetInputBufferByteSize() - theUsedByteSize;
285        
286         if (ioNumberBytes > theUsedByteSize) ioNumberBytes = theUsedByteSize;
287                
288         SInt32 leftOver = mInputBufferStart + ioNumberBytes - mInputBufferByteSize;
289        
290         if(leftOver > 0)
291         {
292                 // need to copy beginning of buffer to the end.
293                 // We cleverly over allocated our buffer space to make this possible.
294                 memcpy(mInputBuffer + mInputBufferByteSize, mInputBuffer, leftOver);
295         }
296        
297         return GetInputBufferStart();
298 }
299
300
301 void    ACSimpleCodec::ReallocateInputBuffer(UInt32 inInputBufferByteSize)
302 {
303         mInputBufferByteSize = inInputBufferByteSize + kBufferPad;
304        
305         //      toss the old buffer
306         delete[] mInputBuffer;
307         mInputBuffer = NULL;
308        
309         //      allocate the new one
310         // allocate extra in order to allow making contiguous data.
311         UInt32 allocSize = 2*inInputBufferByteSize + kBufferPad;
312         mInputBuffer = new Byte[allocSize];
313         memset(mInputBuffer, 0, allocSize);
314        
315         //      reset the ring buffer state
316         mInputBufferStart = 0;
317         mInputBufferEnd = 0;
318 }
319
320 void    ACSimpleCodec::GetPropertyInfo(AudioCodecPropertyID inPropertyID, UInt32& outPropertyDataSize, bool& outWritable)
321 {
322         switch(inPropertyID)
323         {
324                 case kAudioCodecPropertyInputBufferSize:
325                         outPropertyDataSize = sizeof(UInt32);
326                         outWritable = true;
327                         break;
328                 default:
329                         ACBaseCodec::GetPropertyInfo(inPropertyID, outPropertyDataSize, outWritable);
330                         break;
331         }
332
333 }
334
335 void    ACSimpleCodec::SetProperty(AudioCodecPropertyID inPropertyID, UInt32 inPropertyDataSize, const void* inPropertyData)
336 {
337         switch(inPropertyID)
338         {
339                 case kAudioCodecPropertyInputBufferSize:
340                         if(inPropertyDataSize == sizeof(UInt32))
341                         {
342                                 ReallocateInputBuffer(*reinterpret_cast<const UInt32*>(inPropertyData));
343                         }
344                         else
345                         {
346                                 CODEC_THROW(kAudioCodecBadPropertySizeError);
347                         }
348                         break;
349                 default:
350             ACBaseCodec::SetProperty(inPropertyID, inPropertyDataSize, inPropertyData);
351             break;           
352     }
353 }
Note: See TracBrowser for help on using the browser.