Skip to content

Commit

Permalink
Extract picture data from id3 tag if kAudioFilePropertyAlbumArtwork
Browse files Browse the repository at this point in the history
failed
fixes ap4y#18
  • Loading branch information
ap4y committed Oct 12, 2013
1 parent 395e255 commit b670b1b
Showing 1 changed file with 189 additions and 131 deletions.
320 changes: 189 additions & 131 deletions OrigamiEngine/Plugins/CoreAudioDecoder.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@
@interface CoreAudioDecoder () {
id<ORGMSource> _source;
AudioFileID _audioFile;
ExtAudioFileRef _in;
int bitrate;
int bitsPerSample;
int channels;
float frequency;
long totalFrames;
ExtAudioFileRef _in;

int bitrate;
int bitsPerSample;
int channels;
float frequency;
long totalFrames;
}
@property (retain, nonatomic) NSMutableDictionary *metadata;
@end
Expand All @@ -51,22 +51,21 @@ - (void)dealloc {

#pragma mark - ORGMDecoder
+ (NSArray *)fileTypes {
OSStatus err;
UInt32 size;
NSArray *sAudioExtensions;

size = sizeof(sAudioExtensions);
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AllExtensions, 0, NULL,
&size, &sAudioExtensions);
if(noErr != err) {
return nil;
}

return [sAudioExtensions autorelease];
OSStatus err;
UInt32 size;
NSArray *sAudioExtensions;

size = sizeof(sAudioExtensions);
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AllExtensions, 0, NULL, &size, &sAudioExtensions);
if (noErr != err) {
return nil;
}

return [sAudioExtensions autorelease];
}

- (NSDictionary *)properties {
return [NSDictionary dictionaryWithObjectsAndKeys:
return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:channels], @"channels",
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
[NSNumber numberWithInt:bitrate], @"bitrate",
Expand All @@ -82,52 +81,52 @@ - (NSMutableDictionary *)metadata {
}

- (int)readAudio:(void *)buf frames:(UInt32)frames {
OSStatus err;
AudioBufferList bufferList;
UInt32 frameCount;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mNumberChannels = channels;
bufferList.mBuffers[0].mData = buf;
bufferList.mBuffers[0].mDataByteSize = frames * channels * (bitsPerSample/8);
frameCount = frames;
err = ExtAudioFileRead(_in, &frameCount, &bufferList);
if(err != noErr) {
return 0;
}
return frameCount;
OSStatus err;
AudioBufferList bufferList;
UInt32 frameCount;

bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mNumberChannels = channels;
bufferList.mBuffers[0].mData = buf;
bufferList.mBuffers[0].mDataByteSize = frames * channels * (bitsPerSample/8);

frameCount = frames;
err = ExtAudioFileRead(_in, &frameCount, &bufferList);
if (err != noErr) {
return 0;
}

return frameCount;
}

- (BOOL)open:(id<ORGMSource>)source {
self.metadata = [NSMutableDictionary dictionary];
_source = [source retain];
OSStatus result = AudioFileOpenWithCallbacks(_source, audioFile_ReadProc, NULL,
OSStatus result = AudioFileOpenWithCallbacks(_source, audioFile_ReadProc, NULL,
audioFile_GetSizeProc, NULL, 0,
&_audioFile);

if(noErr != result) {

if (noErr != result) {
return NO;
}

result = ExtAudioFileWrapAudioFileID(_audioFile, false, &_in);
if (noErr != result) {
return NO;
}

result = ExtAudioFileWrapAudioFileID(_audioFile, false, &_in);
if(noErr != result) {
return NO;
}

return [self readInfoFromExtAudioFileRef];

return [self readInfoFromExtAudioFileRef];
}

- (long)seek:(long)frame {
OSStatus err;
err = ExtAudioFileSeek(_in, frame);
if(noErr != err) {
return -1;
}
return frame;
OSStatus err;

err = ExtAudioFileSeek(_in, frame);
if (noErr != err) {
return -1;
}

return frame;
}

- (void)close {
Expand All @@ -137,120 +136,179 @@ - (void)close {
}

#pragma mark - private

- (BOOL)readInfoFromExtAudioFileRef {
OSStatus err;
UInt32 size;
AudioStreamBasicDescription asbd;

size = sizeof(asbd);
err = ExtAudioFileGetProperty(_in, kExtAudioFileProperty_FileDataFormat,
&size, &asbd);
if(err != noErr) {
OSStatus err;
UInt32 size;
AudioStreamBasicDescription asbd;

size = sizeof(asbd);
err = ExtAudioFileGetProperty(_in,
kExtAudioFileProperty_FileDataFormat,
&size,
&asbd);
if (err != noErr) {
ExtAudioFileDispose(_in);
return NO;
}

SInt64 total;
size = sizeof(total);
err = ExtAudioFileGetProperty(_in,
kExtAudioFileProperty_FileLengthFrames,
&size,
&total);
if(err != noErr) {
ExtAudioFileDispose(_in);
return NO;
}

SInt64 total;
size = sizeof(total);
err = ExtAudioFileGetProperty(_in, kExtAudioFileProperty_FileLengthFrames,
&size, &total);
if(err != noErr) {
ExtAudioFileDispose(_in);
return NO;
}
totalFrames = (long)total;

return NO;
}
totalFrames = (long)total;

AudioFileID audioFile;
size = sizeof(AudioFileID);
err = ExtAudioFileGetProperty(_in,
kExtAudioFileProperty_AudioFile,
&size,
&audioFile);
kExtAudioFileProperty_AudioFile,
&size,
&audioFile);

if (err == noErr) {
UInt32 dictionarySize = 0;
err = AudioFileGetPropertyInfo(audioFile,
kAudioFilePropertyInfoDictionary,
&dictionarySize,
0);
kAudioFilePropertyInfoDictionary,
&dictionarySize,
0);

if (err == noErr) {
CFDictionaryRef dictionary;
AudioFileGetProperty(audioFile,
kAudioFilePropertyInfoDictionary,
&dictionarySize,
&dictionary);
kAudioFilePropertyInfoDictionary,
&dictionarySize,
&dictionary);
self.metadata = [NSMutableDictionary dictionaryWithDictionary:(NSDictionary *)dictionary];
CFRelease(dictionary);
}

err = AudioFileGetPropertyInfo(audioFile,
kAudioFilePropertyAlbumArtwork,
&dictionarySize,
0);
kAudioFilePropertyAlbumArtwork,
&dictionarySize,
0);

if (err == noErr) {
CFDataRef data;
AudioFileGetProperty(audioFile,
kAudioFilePropertyAlbumArtwork,
&dictionarySize,
&data);
kAudioFilePropertyAlbumArtwork,
&dictionarySize,
&data);

if (data) {
[self.metadata setObject:(NSData *)data forKey:@"picture"];
CFRelease(data);
}
} else {
[self.metadata setObject:[self imageDataFromID3Tag:audioFile] forKey:@"picture"];
}
}

bitrate = 0;
bitsPerSample = asbd.mBitsPerChannel;
channels = asbd.mChannelsPerFrame;
frequency = asbd.mSampleRate;

if(0 == bitsPerSample) {
bitsPerSample = 16;
}

AudioStreamBasicDescription result;
bzero(&result, sizeof(AudioStreamBasicDescription));

result.mFormatID = kAudioFormatLinearPCM;
result.mFormatFlags = kAudioFormatFlagIsSignedInteger |
kLinearPCMFormatFlagIsBigEndian;

result.mSampleRate = frequency;
result.mChannelsPerFrame = channels;
result.mBitsPerChannel = bitsPerSample;

result.mBytesPerPacket = channels * (bitsPerSample / 8);
result.mFramesPerPacket = 1;
result.mBytesPerFrame = channels * (bitsPerSample / 8);

err = ExtAudioFileSetProperty(_in, kExtAudioFileProperty_ClientDataFormat,
sizeof(result), &result);
if(noErr != err) {
ExtAudioFileDispose(_in);
return NO;
}

return YES;

bitrate = 0;
bitsPerSample = asbd.mBitsPerChannel;
channels = asbd.mChannelsPerFrame;
frequency = asbd.mSampleRate;

if(0 == bitsPerSample) {
bitsPerSample = 16;
}

AudioStreamBasicDescription result;
bzero(&result, sizeof(AudioStreamBasicDescription));

result.mFormatID = kAudioFormatLinearPCM;
result.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsBigEndian;

result.mSampleRate = frequency;
result.mChannelsPerFrame = channels;
result.mBitsPerChannel = bitsPerSample;

result.mBytesPerPacket = channels * (bitsPerSample / 8);
result.mFramesPerPacket = 1;
result.mBytesPerFrame = channels * (bitsPerSample / 8);

err = ExtAudioFileSetProperty(_in, kExtAudioFileProperty_ClientDataFormat,
sizeof(result), &result);
if(noErr != err) {
ExtAudioFileDispose(_in);
return NO;
}

return YES;
}

- (NSData *)imageDataFromID3Tag:(AudioFileID)audioFile {

OSStatus err;

UInt32 propertySize = 0;
AudioFileGetPropertyInfo(audioFile,
kAudioFilePropertyID3Tag,
&propertySize,
0);

char *rawID3Tag = (char *)malloc(propertySize);
err = AudioFileGetProperty(audioFile,
kAudioFilePropertyID3Tag,
&propertySize,
rawID3Tag);

if (err != noErr) {
return nil;
}

UInt32 id3TagSize = 0;
UInt32 id3TagSizeLength = sizeof(id3TagSize);
AudioFormatGetProperty(kAudioFormatProperty_ID3TagSize,
propertySize,
rawID3Tag,
&id3TagSizeLength,
&id3TagSize);

CFDictionaryRef id3Dict;
AudioFormatGetProperty(kAudioFormatProperty_ID3TagToDictionary,
propertySize,
rawID3Tag,
&id3TagSize,
&id3Dict);

NSDictionary *tagDict = [NSDictionary dictionaryWithDictionary:(NSDictionary *)id3Dict];
free(rawID3Tag);
CFRelease(id3Dict);

NSDictionary *apicDict = tagDict[@"APIC"];
if (!apicDict) return nil;

NSString *picKey = [[apicDict allKeys] lastObject];
NSDictionary *picDict = apicDict[picKey];
if (!picDict) return nil;

return picDict[@"data"];
}

#pragma mark - callback functions

static OSStatus audioFile_ReadProc(void *inClientData,
SInt64 inPosition,
UInt32 requestCount,
void *buffer,
void *buffer,
UInt32 *actualCount) {
id<ORGMSource> source = inClientData;
[source seek:(long)inPosition whence:0];
*actualCount = [source read:buffer amount:requestCount];
return noErr;
*actualCount = [source read:buffer amount:requestCount];

return noErr;
}

static SInt64 audioFile_GetSizeProc(void *inClientData) {
id<ORGMSource> source = inClientData;
id<ORGMSource> source = inClientData;
SInt64 len = [source size];
return len;
return len;
}

@end

0 comments on commit b670b1b

Please sign in to comment.