root/trunk/PublicUtility/CAStreamBasicDescription.cpp

Revision 1, 15.8 kB (checked in by gbooker, 3 years ago)

Initial Import

Line 
1 /*      Copyright:      © Copyright 2004 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         CAStreamBasicDescription.cpp
40  
41 =============================================================================*/
42
43 #include "CAConditionalMacros.h"
44
45 #include "CAStreamBasicDescription.h"
46
47 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
48         #include <CoreServices/CoreServices.h>
49 #else
50         #include <Endian.h>
51 #endif
52
53 const AudioStreamBasicDescription       CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 };
54
55 CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate,         UInt32 inFormatID,
56                                                                         UInt32 inBytesPerPacket,        UInt32 inFramesPerPacket,
57                                                                         UInt32 inBytesPerFrame,         UInt32 inChannelsPerFrame,
58                                                                         UInt32 inBitsPerChannel,        UInt32 inFormatFlags)
59 {
60         mSampleRate = inSampleRate;
61         mFormatID = inFormatID;
62         mBytesPerPacket = inBytesPerPacket;
63         mFramesPerPacket = inFramesPerPacket;
64         mBytesPerFrame = inBytesPerFrame;
65         mChannelsPerFrame = inChannelsPerFrame;
66         mBitsPerChannel = inBitsPerChannel;
67         mFormatFlags = inFormatFlags;
68 }
69
70 void CAStreamBasicDescription::PrintFormat(FILE *f, const char *indent, const char *name) const
71 {
72         fprintf(f, "%s%s ", indent, name);
73         char formatID[5];
74         *(UInt32 *)formatID = EndianU32_NtoB(mFormatID);
75         formatID[4] = '\0';
76         fprintf(f, "%2ld ch, %6.0f Hz, '%-4.4s' (0x%08lX) ",           
77                                 NumberChannels(), mSampleRate, formatID,
78                                 mFormatFlags);
79         if (mFormatID == kAudioFormatLinearPCM) {
80                 bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat);
81                 int wordSize = SampleWordSize();
82                 const char *endian = (wordSize > 1) ?
83                         ((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : "";
84                 const char *sign = isInt ?
85                         ((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : "";
86                 const char *floatInt = isInt ? "integer" : "float";
87                 char packed[32];
88                 if (PackednessIsSignificant()) {
89                         if (mFormatFlags & kLinearPCMFormatFlagIsPacked)
90                                 sprintf(packed, "packed in %d bytes", wordSize);
91                         else
92                                 sprintf(packed, "unpacked in %d bytes", wordSize);
93                 } else
94                         packed[0] = '\0';
95                 const char *align = AlignmentIsSignificant() ?
96                         ((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : "";
97                 const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : "";
98                 const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : "";
99                
100                 fprintf(f, "%ld-bit%s%s %s%s%s%s%s\n",
101                         mBitsPerChannel, endian, sign, floatInt,
102                         commaSpace, packed, align, deinter);
103         } else
104                 fprintf(f, "%ld bits/channel, %ld bytes/packet, %ld frames/packet, %ld bytes/frame\n",
105                         mBitsPerChannel, mBytesPerPacket, mFramesPerPacket, mBytesPerFrame);
106 }
107
108 void    CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription)
109 {
110         if(ioDescription.mFormatID == kAudioFormatLinearPCM)
111         {
112                 //      we have to doctor the linear PCM format because we always
113                 //      only export 32 bit, native endian, fully packed floats
114                 ioDescription.mBitsPerChannel = sizeof(Float32) * 8;
115                 ioDescription.mBytesPerFrame = sizeof(Float32) * ioDescription.mChannelsPerFrame;
116                 ioDescription.mFramesPerPacket = 1;
117                 ioDescription.mBytesPerPacket = ioDescription.mFramesPerPacket * ioDescription.mBytesPerFrame;
118                
119                 ioDescription.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
120                 ioDescription.mFormatFlags |= kAudioFormatFlagsNativeEndian;
121         }
122 }
123
124 void    CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription)
125 {
126         ioDescription.mSampleRate = 0;
127         ioDescription.mFormatID = 0;
128         ioDescription.mBytesPerPacket = 0;
129         ioDescription.mFramesPerPacket = 0;
130         ioDescription.mBytesPerFrame = 0;
131         ioDescription.mChannelsPerFrame = 0;
132         ioDescription.mBitsPerChannel = 0;
133         ioDescription.mFormatFlags = 0;
134 }
135
136 void    CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription)
137 {
138         if(ioDescription.mSampleRate == 0)
139         {
140                 ioDescription.mSampleRate = inTemplateDescription.mSampleRate;
141         }
142         if(ioDescription.mFormatID == 0)
143         {
144                 ioDescription.mFormatID = inTemplateDescription.mFormatID;
145         }
146         if(ioDescription.mFormatFlags == 0)
147         {
148                 ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags;
149         }
150         if(ioDescription.mBytesPerPacket == 0)
151         {
152                 ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket;
153         }
154         if(ioDescription.mFramesPerPacket == 0)
155         {
156                 ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket;
157         }
158         if(ioDescription.mBytesPerFrame == 0)
159         {
160                 ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame;
161         }
162         if(ioDescription.mChannelsPerFrame == 0)
163         {
164                 ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame;
165         }
166         if(ioDescription.mBitsPerChannel == 0)
167         {
168                 ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel;
169         }
170 }
171
172 void    CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate)
173 {
174         switch(inDescription.mFormatID)
175         {
176                 case kAudioFormatLinearPCM:
177                         {
178                                 const char* theEndianString = NULL;
179                                 if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0)
180                                 {
181                                         #if     TARGET_RT_LITTLE_ENDIAN
182                                                 theEndianString = "Big Endian";
183                                         #endif
184                                 }
185                                 else
186                                 {
187                                         #if     TARGET_RT_BIG_ENDIAN
188                                                 theEndianString = "Little Endian";
189                                         #endif
190                                 }
191                                
192                                 const char* theKindString = NULL;
193                                 if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
194                                 {
195                                         theKindString = (inAbbreviate ? "Float" : "Floating Point");
196                                 }
197                                 else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
198                                 {
199                                         theKindString = (inAbbreviate ? "SInt" : "Signed Integer");
200                                 }
201                                 else
202                                 {
203                                         theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer");
204                                 }
205                                
206                                 const char* thePackingString = NULL;
207                                 if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0)
208                                 {
209                                         if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0)
210                                         {
211                                                 thePackingString = "High";
212                                         }
213                                         else
214                                         {
215                                                 thePackingString = "Low";
216                                         }
217                                 }
218                                
219                                 if(inAbbreviate)
220                                 {
221                                         if(theEndianString != NULL)
222                                         {
223                                                 if(thePackingString != NULL)
224                                                 {
225                                                         sprintf(outName, "%d Ch %s %s %s%d/%s%d", (int)inDescription.mChannelsPerFrame, theEndianString, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
226                                                 }
227                                                 else
228                                                 {
229                                                         sprintf(outName, "%d Ch %s %s%d", (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel);
230                                                 }
231                                         }
232                                         else
233                                         {
234                                                 if(thePackingString != NULL)
235                                                 {
236                                                         sprintf(outName, "%d Ch %s %s%d/%s%d", (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8));
237                                                 }
238                                                 else
239                                                 {
240                                                         sprintf(outName, "%d Ch %s%d", (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel);
241                                                 }
242                                         }
243                                 }
244                                 else
245                                 {
246                                         if(theEndianString != NULL)
247                                         {
248                                                 if(thePackingString != NULL)
249                                                 {
250                                                         sprintf(outName, "%d Channel %d Bit %s %s Aligned %s in %d Bits", (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
251                                                 }
252                                                 else
253                                                 {
254                                                         sprintf(outName, "%d Channel %d Bit %s %s", (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString);
255                                                 }
256                                         }
257                                         else
258                                         {
259                                                 sprintf(outName, "%d Channel %d Bit %s", (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString);
260                                                 if(thePackingString != NULL)
261                                                 {
262                                                         sprintf(outName, "%d Channel %d Bit %s Aligned %s in %d Bits", (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
263                                                 }
264                                                 else
265                                                 {
266                                                         sprintf(outName, "%d Channel %d Bit %s", (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString);
267                                                 }
268                                         }
269                                 }
270                         }
271                         break;
272                
273                 case kAudioFormatAC3:
274                         strcpy(outName, "AC-3");
275                         break;
276                
277                 case kAudioFormat60958AC3:
278                         strcpy(outName, "AC-3 for SPDIF");
279                         break;
280                
281                 default:
282                         {
283                                 char* the4CCString = (char*)&inDescription.mFormatID;
284                                 outName[0] = the4CCString[0];
285                                 outName[1] = the4CCString[1];
286                                 outName[2] = the4CCString[2];
287                                 outName[3] = the4CCString[3];
288                                 outName[4] = 0;
289                         }
290                         break;
291         };
292 }
293
294 #if CoreAudio_Debug
295 #include "CALogMacros.h"
296
297 void    CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc)
298 {
299         PrintFloat              ("  Sample Rate:        ", inDesc.mSampleRate);
300         Print4CharCode  ("  Format ID:          ", inDesc.mFormatID);
301         PrintHex                ("  Format Flags:       ", inDesc.mFormatFlags);
302         PrintInt                ("  Bytes per Packet:   ", inDesc.mBytesPerPacket);
303         PrintInt                ("  Frames per Packet:  ", inDesc.mFramesPerPacket);
304         PrintInt                ("  Bytes per Frame:    ", inDesc.mBytesPerFrame);
305         PrintInt                ("  Channels per Frame: ", inDesc.mChannelsPerFrame);
306         PrintInt                ("  Bits per Channel:   ", inDesc.mBitsPerChannel);
307 }
308 #endif
309
310 bool    operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
311 {
312         bool theAnswer = false;
313         bool isDone = false;
314        
315         //      note that if either side is 0, that field is skipped
316        
317         //      format ID is the first order sort
318         if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0)))
319         {
320                 if(x.mFormatID != y.mFormatID)
321                 {
322                         //      formats are sorted numerically except that linear
323                         //      PCM is always first
324                         if(x.mFormatID == kAudioFormatLinearPCM)
325                         {
326                                 theAnswer = true;
327                         }
328                         else if(y.mFormatID == kAudioFormatLinearPCM)
329                         {
330                                 theAnswer = false;
331                         }
332                         else
333                         {
334                                 theAnswer = x.mFormatID < y.mFormatID;
335                         }
336                         isDone = true;
337                 }
338         }
339        
340         //      floating point vs integer for linear PCM only
341         if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
342         {
343                 if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat))
344                 {
345                         //      floating point is better than integer
346                         theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat;
347                         isDone = true;
348                 }
349         }
350        
351         //      bit depth
352         if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0)))
353         {
354                 if(x.mBitsPerChannel != y.mBitsPerChannel)
355                 {
356                         //      deeper bit depths are higher quality
357                         theAnswer = x.mBitsPerChannel < y.mBitsPerChannel;
358                         isDone = true;
359                 }
360         }
361        
362         //      sample rate
363         if((!isDone) && ((x.mSampleRate != 0) && (y.mSampleRate != 0)))
364         {
365                 if(x.mSampleRate != y.mSampleRate)
366                 {
367                         //      higher sample rates are higher quality
368                         theAnswer = x.mSampleRate < y.mSampleRate;
369                         isDone = true;
370                 }
371         }
372        
373         //      number of channels
374         if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0)))
375         {
376                 if(x.mChannelsPerFrame != y.mChannelsPerFrame)
377                 {
378                         //      more channels is higher quality
379                         theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame;
380                         isDone = true;
381                 }
382         }
383        
384         return theAnswer;
385 }
386
387 static bool MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
388 {
389         UInt32 xFlags = x.mFormatFlags;
390         UInt32 yFlags = y.mFormatFlags;
391        
392         // match wildcards
393         if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0)
394                 return true;
395        
396         if (x.mFormatID == kAudioFormatLinearPCM)
397         {                               
398                 // knock off the all clear flag
399                 xFlags = xFlags & ~kAudioFormatFlagsAreAllClear;
400                 yFlags = yFlags & ~kAudioFormatFlagsAreAllClear;
401        
402                 // if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit.
403                 if (xFlags & yFlags & kAudioFormatFlagIsPacked) {
404                         xFlags = xFlags & ~kAudioFormatFlagIsAlignedHigh;
405                         yFlags = yFlags & ~kAudioFormatFlagIsAlignedHigh;
406                 }
407                
408                 // if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit.
409                 if (xFlags & yFlags & kAudioFormatFlagIsFloat) {
410                         xFlags = xFlags & ~kAudioFormatFlagIsSignedInteger;
411                         yFlags = yFlags & ~kAudioFormatFlagIsSignedInteger;
412                 }
413                
414                 //      if the bit depth is 8 bits or less and the format is packed, we don't care about endianness
415                 if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
416                 {
417                         xFlags = xFlags & ~kAudioFormatFlagIsBigEndian;
418                 }
419                 if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
420                 {
421                         yFlags = yFlags & ~kAudioFormatFlagIsBigEndian;
422                 }
423         }
424         return xFlags == yFlags;
425 }
426
427 bool    operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
428 {
429         //      the semantics for equality are:
430         //              1) Values must match exactly
431         //              2) wildcard's are ignored in the comparison
432        
433 #define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name))
434        
435         return
436                         //      check the sample rate
437                 MATCH(mSampleRate)
438                
439                         //      check the format ids
440                 && MATCH(mFormatID)
441                
442                         //      check the format flags
443                 && MatchFormatFlags(x, y) 
444                        
445                         //      check the bytes per packet
446                 && MATCH(mBytesPerPacket)
447                
448                         //      check the frames per packet
449                 && MATCH(mFramesPerPacket)
450                
451                         //      check the bytes per frame
452                 && MATCH(mBytesPerFrame)
453                
454                         //      check the channels per frame
455                 && MATCH(mChannelsPerFrame)
456                
457                         //      check the channels per frame
458                 && MATCH(mBitsPerChannel) ;
459 }
460
461 bool SanityCheck(const AudioStreamBasicDescription& x)
462 {
463         return (x.mSampleRate >= 0.);
464 }
Note: See TracBrowser for help on using the browser.