Implement dynamic metadata reading for streams
Supported by FFmpeg, FLAC, Ogg Vorbis, and Opus. Signed-off-by: Christopher Snowhill <kode54@gmail.com>CQTexperiment
parent
cdf27e4786
commit
0012d1b17e
|
@ -163,7 +163,10 @@
|
||||||
|
|
||||||
if(amountInBuffer < CHUNK_SIZE) {
|
if(amountInBuffer < CHUNK_SIZE) {
|
||||||
int framesToRead = CHUNK_SIZE - amountInBuffer;
|
int framesToRead = CHUNK_SIZE - amountInBuffer;
|
||||||
int framesRead = [decoder readAudio:((char *)inputBuffer) + bytesInBuffer frames:framesToRead];
|
int framesRead;
|
||||||
|
@autoreleasepool {
|
||||||
|
framesRead = [decoder readAudio:((char *)inputBuffer) + bytesInBuffer frames:framesToRead];
|
||||||
|
}
|
||||||
|
|
||||||
if(framesRead > 0 && !seekError) {
|
if(framesRead > 0 && !seekError) {
|
||||||
amountInBuffer += framesRead;
|
amountInBuffer += framesRead;
|
||||||
|
|
|
@ -66,8 +66,37 @@
|
||||||
17B5E1DE0CC074D3004E2AF4 /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = 17B5E1970CC074D3004E2AF4 /* window.c */; };
|
17B5E1DE0CC074D3004E2AF4 /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = 17B5E1970CC074D3004E2AF4 /* window.c */; };
|
||||||
17B5E2C00CC07904004E2AF4 /* stream_encoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 17B5E1950CC074D3004E2AF4 /* stream_encoder.c */; };
|
17B5E2C00CC07904004E2AF4 /* stream_encoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 17B5E1950CC074D3004E2AF4 /* stream_encoder.c */; };
|
||||||
17B5E2C10CC07905004E2AF4 /* stream_encoder_framing.c in Sources */ = {isa = PBXBuildFile; fileRef = 17B5E1960CC074D3004E2AF4 /* stream_encoder_framing.c */; };
|
17B5E2C10CC07905004E2AF4 /* stream_encoder_framing.c in Sources */ = {isa = PBXBuildFile; fileRef = 17B5E1960CC074D3004E2AF4 /* stream_encoder_framing.c */; };
|
||||||
|
8356BD0527B3A4C20074E50C /* ogg_mapping.c in Sources */ = {isa = PBXBuildFile; fileRef = 8356BD0127B3A4C20074E50C /* ogg_mapping.c */; };
|
||||||
|
8356BD0627B3A4C20074E50C /* ogg_encoder_aspect.c in Sources */ = {isa = PBXBuildFile; fileRef = 8356BD0227B3A4C20074E50C /* ogg_encoder_aspect.c */; };
|
||||||
|
8356BD0727B3A4C20074E50C /* ogg_decoder_aspect.c in Sources */ = {isa = PBXBuildFile; fileRef = 8356BD0327B3A4C20074E50C /* ogg_decoder_aspect.c */; };
|
||||||
|
8356BD0827B3A4C20074E50C /* ogg_helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 8356BD0427B3A4C20074E50C /* ogg_helper.c */; };
|
||||||
|
8356BD1327B3A4E20074E50C /* Ogg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8356BD0F27B3A4D90074E50C /* Ogg.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
8356BD0E27B3A4D90074E50C /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 8356BD0927B3A4D90074E50C /* Ogg.xcodeproj */;
|
||||||
|
proxyType = 2;
|
||||||
|
remoteGlobalIDString = 8D07F2C80486CC7A007CD1D0;
|
||||||
|
remoteInfo = Ogg;
|
||||||
|
};
|
||||||
|
8356BD1027B3A4D90074E50C /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 8356BD0927B3A4D90074E50C /* Ogg.xcodeproj */;
|
||||||
|
proxyType = 2;
|
||||||
|
remoteGlobalIDString = 734FB2E50B18B33E00D561D7;
|
||||||
|
remoteInfo = "libogg (static)";
|
||||||
|
};
|
||||||
|
8356BD1427B3A4E70074E50C /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 8356BD0927B3A4D90074E50C /* Ogg.xcodeproj */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
|
||||||
|
remoteInfo = Ogg;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||||
0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
|
0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
|
||||||
|
@ -131,6 +160,11 @@
|
||||||
17B5E1950CC074D3004E2AF4 /* stream_encoder.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = stream_encoder.c; sourceTree = "<group>"; };
|
17B5E1950CC074D3004E2AF4 /* stream_encoder.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = stream_encoder.c; sourceTree = "<group>"; };
|
||||||
17B5E1960CC074D3004E2AF4 /* stream_encoder_framing.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = stream_encoder_framing.c; sourceTree = "<group>"; };
|
17B5E1960CC074D3004E2AF4 /* stream_encoder_framing.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = stream_encoder_framing.c; sourceTree = "<group>"; };
|
||||||
17B5E1970CC074D3004E2AF4 /* window.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = window.c; sourceTree = "<group>"; };
|
17B5E1970CC074D3004E2AF4 /* window.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = window.c; sourceTree = "<group>"; };
|
||||||
|
8356BD0127B3A4C20074E50C /* ogg_mapping.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogg_mapping.c; sourceTree = "<group>"; };
|
||||||
|
8356BD0227B3A4C20074E50C /* ogg_encoder_aspect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogg_encoder_aspect.c; sourceTree = "<group>"; };
|
||||||
|
8356BD0327B3A4C20074E50C /* ogg_decoder_aspect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogg_decoder_aspect.c; sourceTree = "<group>"; };
|
||||||
|
8356BD0427B3A4C20074E50C /* ogg_helper.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogg_helper.c; sourceTree = "<group>"; };
|
||||||
|
8356BD0927B3A4D90074E50C /* Ogg.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Ogg.xcodeproj; path = ../Ogg/macosx/Ogg.xcodeproj; sourceTree = "<group>"; };
|
||||||
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||||
8DC2EF5B0486A6940098B216 /* FLAC.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FLAC.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
8DC2EF5B0486A6940098B216 /* FLAC.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FLAC.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D2F7E79907B2D74100F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
D2F7E79907B2D74100F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
||||||
|
@ -141,6 +175,7 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
8356BD1327B3A4E20074E50C /* Ogg.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -163,6 +198,7 @@
|
||||||
089C1665FE841158C02AAC07 /* Resources */,
|
089C1665FE841158C02AAC07 /* Resources */,
|
||||||
0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
|
0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
|
||||||
034768DFFF38A50411DB9C8B /* Products */,
|
034768DFFF38A50411DB9C8B /* Products */,
|
||||||
|
8356BD1227B3A4E20074E50C /* Frameworks */,
|
||||||
);
|
);
|
||||||
name = flac;
|
name = flac;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -195,6 +231,7 @@
|
||||||
1058C7B2FEA5585E11CA2CBB /* Other Frameworks */ = {
|
1058C7B2FEA5585E11CA2CBB /* Other Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
8356BD0927B3A4D90074E50C /* Ogg.xcodeproj */,
|
||||||
0867D6A5FE840307C02AAC07 /* AppKit.framework */,
|
0867D6A5FE840307C02AAC07 /* AppKit.framework */,
|
||||||
D2F7E79907B2D74100F64583 /* CoreData.framework */,
|
D2F7E79907B2D74100F64583 /* CoreData.framework */,
|
||||||
0867D69BFE84028FC02AAC07 /* Foundation.framework */,
|
0867D69BFE84028FC02AAC07 /* Foundation.framework */,
|
||||||
|
@ -280,9 +317,13 @@
|
||||||
17B5E1880CC074D3004E2AF4 /* memory.c */,
|
17B5E1880CC074D3004E2AF4 /* memory.c */,
|
||||||
17B5E1890CC074D3004E2AF4 /* metadata_iterators.c */,
|
17B5E1890CC074D3004E2AF4 /* metadata_iterators.c */,
|
||||||
17B5E18A0CC074D3004E2AF4 /* metadata_object.c */,
|
17B5E18A0CC074D3004E2AF4 /* metadata_object.c */,
|
||||||
|
8356BD0327B3A4C20074E50C /* ogg_decoder_aspect.c */,
|
||||||
|
8356BD0227B3A4C20074E50C /* ogg_encoder_aspect.c */,
|
||||||
|
8356BD0427B3A4C20074E50C /* ogg_helper.c */,
|
||||||
|
8356BD0127B3A4C20074E50C /* ogg_mapping.c */,
|
||||||
17B5E1940CC074D3004E2AF4 /* stream_decoder.c */,
|
17B5E1940CC074D3004E2AF4 /* stream_decoder.c */,
|
||||||
17B5E1950CC074D3004E2AF4 /* stream_encoder.c */,
|
|
||||||
17B5E1960CC074D3004E2AF4 /* stream_encoder_framing.c */,
|
17B5E1960CC074D3004E2AF4 /* stream_encoder_framing.c */,
|
||||||
|
17B5E1950CC074D3004E2AF4 /* stream_encoder.c */,
|
||||||
17B5E1970CC074D3004E2AF4 /* window.c */,
|
17B5E1970CC074D3004E2AF4 /* window.c */,
|
||||||
);
|
);
|
||||||
path = libFLAC;
|
path = libFLAC;
|
||||||
|
@ -333,6 +374,22 @@
|
||||||
path = protected;
|
path = protected;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
8356BD0A27B3A4D90074E50C /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
8356BD0F27B3A4D90074E50C /* Ogg.framework */,
|
||||||
|
8356BD1127B3A4D90074E50C /* libogg.a */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
8356BD1227B3A4E20074E50C /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXHeadersBuildPhase section */
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
|
@ -400,6 +457,7 @@
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
|
8356BD1527B3A4E70074E50C /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = "FLAC Framework";
|
name = "FLAC Framework";
|
||||||
productInstallPath = "$(HOME)/Library/Frameworks";
|
productInstallPath = "$(HOME)/Library/Frameworks";
|
||||||
|
@ -432,6 +490,12 @@
|
||||||
mainGroup = 0867D691FE84028FC02AAC07 /* flac */;
|
mainGroup = 0867D691FE84028FC02AAC07 /* flac */;
|
||||||
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
|
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
|
projectReferences = (
|
||||||
|
{
|
||||||
|
ProductGroup = 8356BD0A27B3A4D90074E50C /* Products */;
|
||||||
|
ProjectRef = 8356BD0927B3A4D90074E50C /* Ogg.xcodeproj */;
|
||||||
|
},
|
||||||
|
);
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
8DC2EF4F0486A6940098B216 /* FLAC Framework */,
|
8DC2EF4F0486A6940098B216 /* FLAC Framework */,
|
||||||
|
@ -439,6 +503,23 @@
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXReferenceProxy section */
|
||||||
|
8356BD0F27B3A4D90074E50C /* Ogg.framework */ = {
|
||||||
|
isa = PBXReferenceProxy;
|
||||||
|
fileType = wrapper.framework;
|
||||||
|
path = Ogg.framework;
|
||||||
|
remoteRef = 8356BD0E27B3A4D90074E50C /* PBXContainerItemProxy */;
|
||||||
|
sourceTree = BUILT_PRODUCTS_DIR;
|
||||||
|
};
|
||||||
|
8356BD1127B3A4D90074E50C /* libogg.a */ = {
|
||||||
|
isa = PBXReferenceProxy;
|
||||||
|
fileType = archive.ar;
|
||||||
|
path = libogg.a;
|
||||||
|
remoteRef = 8356BD1027B3A4D90074E50C /* PBXContainerItemProxy */;
|
||||||
|
sourceTree = BUILT_PRODUCTS_DIR;
|
||||||
|
};
|
||||||
|
/* End PBXReferenceProxy section */
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
8DC2EF520486A6940098B216 /* Resources */ = {
|
8DC2EF520486A6940098B216 /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
|
@ -455,6 +536,7 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
17B5E1AC0CC074D3004E2AF4 /* bitmath.c in Sources */,
|
17B5E1AC0CC074D3004E2AF4 /* bitmath.c in Sources */,
|
||||||
|
8356BD0827B3A4C20074E50C /* ogg_helper.c in Sources */,
|
||||||
17B5E1AD0CC074D3004E2AF4 /* bitreader.c in Sources */,
|
17B5E1AD0CC074D3004E2AF4 /* bitreader.c in Sources */,
|
||||||
17B5E1AE0CC074D3004E2AF4 /* bitwriter.c in Sources */,
|
17B5E1AE0CC074D3004E2AF4 /* bitwriter.c in Sources */,
|
||||||
17B5E1AF0CC074D3004E2AF4 /* cpu.c in Sources */,
|
17B5E1AF0CC074D3004E2AF4 /* cpu.c in Sources */,
|
||||||
|
@ -464,9 +546,12 @@
|
||||||
17B5E1B30CC074D3004E2AF4 /* format.c in Sources */,
|
17B5E1B30CC074D3004E2AF4 /* format.c in Sources */,
|
||||||
17B5E1D00CC074D3004E2AF4 /* lpc.c in Sources */,
|
17B5E1D00CC074D3004E2AF4 /* lpc.c in Sources */,
|
||||||
17B5E1D10CC074D3004E2AF4 /* md5.c in Sources */,
|
17B5E1D10CC074D3004E2AF4 /* md5.c in Sources */,
|
||||||
|
8356BD0727B3A4C20074E50C /* ogg_decoder_aspect.c in Sources */,
|
||||||
17B5E1D20CC074D3004E2AF4 /* memory.c in Sources */,
|
17B5E1D20CC074D3004E2AF4 /* memory.c in Sources */,
|
||||||
17B5E1D30CC074D3004E2AF4 /* metadata_iterators.c in Sources */,
|
17B5E1D30CC074D3004E2AF4 /* metadata_iterators.c in Sources */,
|
||||||
|
8356BD0527B3A4C20074E50C /* ogg_mapping.c in Sources */,
|
||||||
17B5E1D40CC074D3004E2AF4 /* metadata_object.c in Sources */,
|
17B5E1D40CC074D3004E2AF4 /* metadata_object.c in Sources */,
|
||||||
|
8356BD0627B3A4C20074E50C /* ogg_encoder_aspect.c in Sources */,
|
||||||
17B5E1DB0CC074D3004E2AF4 /* stream_decoder.c in Sources */,
|
17B5E1DB0CC074D3004E2AF4 /* stream_decoder.c in Sources */,
|
||||||
17B5E1DE0CC074D3004E2AF4 /* window.c in Sources */,
|
17B5E1DE0CC074D3004E2AF4 /* window.c in Sources */,
|
||||||
17B5E2C00CC07904004E2AF4 /* stream_encoder.c in Sources */,
|
17B5E2C00CC07904004E2AF4 /* stream_encoder.c in Sources */,
|
||||||
|
@ -476,6 +561,14 @@
|
||||||
};
|
};
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
8356BD1527B3A4E70074E50C /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
name = Ogg;
|
||||||
|
targetProxy = 8356BD1427B3A4E70074E50C /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
1DEB91AE08733DA50010E9CD /* Debug */ = {
|
1DEB91AE08733DA50010E9CD /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
@ -488,6 +581,7 @@
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
DYLIB_CURRENT_VERSION = 1;
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
FRAMEWORK_VERSION = A;
|
FRAMEWORK_VERSION = A;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
GCC_ENABLE_SYMBOL_SEPARATION = YES;
|
GCC_ENABLE_SYMBOL_SEPARATION = YES;
|
||||||
|
@ -508,7 +602,7 @@
|
||||||
"$(OTHER_CFLAGS_QUOTED_1)",
|
"$(OTHER_CFLAGS_QUOTED_1)",
|
||||||
"-D__MACOSX__",
|
"-D__MACOSX__",
|
||||||
"-DHAVE_LROUND",
|
"-DHAVE_LROUND",
|
||||||
"-DFLAC__HAS_OGG=0",
|
"-DFLAC__HAS_OGG=1",
|
||||||
);
|
);
|
||||||
OTHER_CFLAGS_QUOTED_1 = "-DVERSION=\\\"1.3.3\\\" -DPACKAGE_VERSION=\\\"1.3.3\\\"";
|
OTHER_CFLAGS_QUOTED_1 = "-DVERSION=\\\"1.3.3\\\" -DPACKAGE_VERSION=\\\"1.3.3\\\"";
|
||||||
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
|
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
|
||||||
|
@ -535,6 +629,7 @@
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
DYLIB_CURRENT_VERSION = 1;
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
FRAMEWORK_VERSION = A;
|
FRAMEWORK_VERSION = A;
|
||||||
GCC_ENABLE_SYMBOL_SEPARATION = YES;
|
GCC_ENABLE_SYMBOL_SEPARATION = YES;
|
||||||
GCC_MODEL_TUNING = G5;
|
GCC_MODEL_TUNING = G5;
|
||||||
|
@ -553,7 +648,7 @@
|
||||||
"$(OTHER_CFLAGS_QUOTED_1)",
|
"$(OTHER_CFLAGS_QUOTED_1)",
|
||||||
"-D__MACOSX__",
|
"-D__MACOSX__",
|
||||||
"-DHAVE_LROUND",
|
"-DHAVE_LROUND",
|
||||||
"-DFLAC__HAS_OGG=0",
|
"-DFLAC__HAS_OGG=1",
|
||||||
);
|
);
|
||||||
OTHER_CFLAGS_QUOTED_1 = "-DVERSION=\\\"1.3.3\\\" -DPACKAGE_VERSION=\\\"1.3.3\\\"";
|
OTHER_CFLAGS_QUOTED_1 = "-DVERSION=\\\"1.3.3\\\" -DPACKAGE_VERSION=\\\"1.3.3\\\"";
|
||||||
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
|
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
8356BCE727B37C6F0074E50C /* NSDictionary+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+Merge.m"; path = "../../Utils/NSDictionary+Merge.m"; sourceTree = "<group>"; };
|
8356BCE727B37C6F0074E50C /* NSDictionary+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+Merge.m"; path = "../../Utils/NSDictionary+Merge.m"; sourceTree = "<group>"; };
|
||||||
8356BCE827B37C6F0074E50C /* NSDictionary+Merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Merge.h"; path = "../../Utils/NSDictionary+Merge.h"; sourceTree = "<group>"; };
|
8356BCE827B37C6F0074E50C /* NSDictionary+Merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Merge.h"; path = "../../Utils/NSDictionary+Merge.h"; sourceTree = "<group>"; };
|
||||||
8356BCEA27B37DA40074E50C /* TagLibID3v2Reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TagLibID3v2Reader.h; path = ../TagLib/TagLibID3v2Reader.h; sourceTree = "<group>"; };
|
8356BCEA27B37DA40074E50C /* TagLibID3v2Reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TagLibID3v2Reader.h; path = ../TagLib/TagLibID3v2Reader.h; sourceTree = "<group>"; };
|
||||||
|
8356BD1A27B3D06F0074E50C /* HTTPSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSource.h; path = ../HTTPSource/HTTPSource.h; sourceTree = "<group>"; };
|
||||||
8384913818081F6C00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
8384913818081F6C00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
||||||
83AA7D08279EBCC600087AA4 /* libavcodec.59.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libavcodec.59.dylib; path = ../../ThirdParty/ffmpeg/lib/libavcodec.59.dylib; sourceTree = "<group>"; };
|
83AA7D08279EBCC600087AA4 /* libavcodec.59.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libavcodec.59.dylib; path = ../../ThirdParty/ffmpeg/lib/libavcodec.59.dylib; sourceTree = "<group>"; };
|
||||||
83AA7D09279EBCC600087AA4 /* libavutil.57.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libavutil.57.dylib; path = ../../ThirdParty/ffmpeg/lib/libavutil.57.dylib; sourceTree = "<group>"; };
|
83AA7D09279EBCC600087AA4 /* libavutil.57.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libavutil.57.dylib; path = ../../ThirdParty/ffmpeg/lib/libavutil.57.dylib; sourceTree = "<group>"; };
|
||||||
|
@ -139,6 +140,7 @@
|
||||||
08FB77AFFE84173DC02AAC07 /* Classes */ = {
|
08FB77AFFE84173DC02AAC07 /* Classes */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
8356BD1A27B3D06F0074E50C /* HTTPSource.h */,
|
||||||
8356BCEA27B37DA40074E50C /* TagLibID3v2Reader.h */,
|
8356BCEA27B37DA40074E50C /* TagLibID3v2Reader.h */,
|
||||||
8356BCE827B37C6F0074E50C /* NSDictionary+Merge.h */,
|
8356BCE827B37C6F0074E50C /* NSDictionary+Merge.h */,
|
||||||
8356BCE727B37C6F0074E50C /* NSDictionary+Merge.m */,
|
8356BCE727B37C6F0074E50C /* NSDictionary+Merge.m */,
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
BOOL endOfAudio;
|
BOOL endOfAudio;
|
||||||
|
|
||||||
int metadataIndex;
|
int metadataIndex;
|
||||||
|
NSString *genre;
|
||||||
NSString *artist;
|
NSString *artist;
|
||||||
NSString *title;
|
NSString *title;
|
||||||
NSString *album;
|
NSString *album;
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
#import "Logging.h"
|
#import "Logging.h"
|
||||||
|
|
||||||
|
#import "HTTPSource.h"
|
||||||
|
|
||||||
#define ST_BUFF 2048
|
#define ST_BUFF 2048
|
||||||
|
|
||||||
int ffmpeg_read(void *opaque, uint8_t *buf, int buf_size) {
|
int ffmpeg_read(void *opaque, uint8_t *buf, int buf_size) {
|
||||||
|
@ -82,8 +84,9 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
|
||||||
// register all available codecs
|
// register all available codecs
|
||||||
|
|
||||||
NSURL *url = [s url];
|
NSURL *url = [s url];
|
||||||
if([[url scheme] isEqualToString:@"http"] ||
|
if(([[url scheme] isEqualToString:@"http"] ||
|
||||||
[[url scheme] isEqualToString:@"https"]) {
|
[[url scheme] isEqualToString:@"https"]) &&
|
||||||
|
[[url pathExtension] isEqualToString:@"m3u8"]) {
|
||||||
source = nil;
|
source = nil;
|
||||||
[s close];
|
[s close];
|
||||||
|
|
||||||
|
@ -95,20 +98,13 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVDictionary *dict = NULL;
|
|
||||||
|
|
||||||
av_dict_set_int(&dict, "icy", 1, 0); // Enable Icy interval metadata, if supported
|
|
||||||
|
|
||||||
NSString *urlString = [url absoluteString];
|
NSString *urlString = [url absoluteString];
|
||||||
if((errcode = avformat_open_input(&formatCtx, [urlString UTF8String], NULL, &dict)) < 0) {
|
if((errcode = avformat_open_input(&formatCtx, [urlString UTF8String], NULL, NULL)) < 0) {
|
||||||
av_dict_free(&dict);
|
|
||||||
char errDescr[4096];
|
char errDescr[4096];
|
||||||
av_strerror(errcode, errDescr, 4096);
|
av_strerror(errcode, errDescr, 4096);
|
||||||
ALog(@"Error opening file, errcode = %d, error = %s", errcode, errDescr);
|
ALog(@"Error opening file, errcode = %d, error = %s", errcode, errDescr);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
av_dict_free(&dict);
|
|
||||||
} else {
|
} else {
|
||||||
buffer = av_malloc(32 * 1024);
|
buffer = av_malloc(32 * 1024);
|
||||||
if(!buffer) {
|
if(!buffer) {
|
||||||
|
@ -415,6 +411,7 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
|
||||||
|
|
||||||
seekable = [s seekable];
|
seekable = [s seekable];
|
||||||
|
|
||||||
|
genre = @"";
|
||||||
album = @"";
|
album = @"";
|
||||||
artist = @"";
|
artist = @"";
|
||||||
title = @"";
|
title = @"";
|
||||||
|
@ -465,6 +462,7 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
|
||||||
|
|
||||||
- (void)updateMetadata {
|
- (void)updateMetadata {
|
||||||
const AVDictionaryEntry *tag = NULL;
|
const AVDictionaryEntry *tag = NULL;
|
||||||
|
NSString *_genre = genre;
|
||||||
NSString *_album = album;
|
NSString *_album = album;
|
||||||
NSString *_artist = artist;
|
NSString *_artist = artist;
|
||||||
NSString *_title = title;
|
NSString *_title = title;
|
||||||
|
@ -481,6 +479,8 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
|
||||||
}
|
}
|
||||||
} else if(!strcasecmp(tag->key, "icy-url")) {
|
} else if(!strcasecmp(tag->key, "icy-url")) {
|
||||||
_album = [NSString stringWithUTF8String:tag->value];
|
_album = [NSString stringWithUTF8String:tag->value];
|
||||||
|
} else if(!strcasecmp(tag->key, "icy-genre")) {
|
||||||
|
_genre = [NSString stringWithUTF8String:tag->value];
|
||||||
} else if(!strcasecmp(tag->key, "artist")) {
|
} else if(!strcasecmp(tag->key, "artist")) {
|
||||||
_artist = [NSString stringWithUTF8String:tag->value];
|
_artist = [NSString stringWithUTF8String:tag->value];
|
||||||
} else if(!strcasecmp(tag->key, "title")) {
|
} else if(!strcasecmp(tag->key, "title")) {
|
||||||
|
@ -489,9 +489,23 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(![_album isEqual:album] ||
|
Class sourceClass = [source class];
|
||||||
|
if([sourceClass isEqual:NSClassFromString(@"HTTPSource")]) {
|
||||||
|
HTTPSource *httpSource = (HTTPSource *)source;
|
||||||
|
if([httpSource hasMetadata]) {
|
||||||
|
NSDictionary *metadata = [httpSource metadata];
|
||||||
|
_genre = [metadata valueForKey:@"genre"];
|
||||||
|
_album = [metadata valueForKey:@"album"];
|
||||||
|
_artist = [metadata valueForKey:@"artist"];
|
||||||
|
_title = [metadata valueForKey:@"title"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(![_genre isEqual:genre] ||
|
||||||
|
![_album isEqual:album] ||
|
||||||
![_artist isEqual:artist] ||
|
![_artist isEqual:artist] ||
|
||||||
![_title isEqual:title]) {
|
![_title isEqual:title]) {
|
||||||
|
genre = _genre;
|
||||||
album = _album;
|
album = _album;
|
||||||
artist = _artist;
|
artist = _artist;
|
||||||
title = _title;
|
title = _title;
|
||||||
|
@ -725,7 +739,7 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *)metadata {
|
- (NSDictionary *)metadata {
|
||||||
return [NSDictionary dictionaryByMerging:@{ @"album": album, @"artist": artist, @"title": title } with:id3Metadata];
|
return [NSDictionary dictionaryByMerging:@{ @"genre": genre, @"album": album, @"artist": artist, @"title": title } with:id3Metadata];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)fileTypes {
|
+ (NSArray *)fileTypes {
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
17C93F040B8FF67A008627D6 /* FlacDecoder.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = FlacDecoder.m; sourceTree = "<group>"; };
|
17C93F040B8FF67A008627D6 /* FlacDecoder.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = FlacDecoder.m; sourceTree = "<group>"; };
|
||||||
17F5641A0C3BDC460019975C /* flac.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = flac.xcodeproj; path = ../../Frameworks/FLAC/flac.xcodeproj; sourceTree = SOURCE_ROOT; };
|
17F5641A0C3BDC460019975C /* flac.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = flac.xcodeproj; path = ../../Frameworks/FLAC/flac.xcodeproj; sourceTree = SOURCE_ROOT; };
|
||||||
32DBCF630370AF2F00C91783 /* Flac_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Flac_Prefix.pch; sourceTree = "<group>"; };
|
32DBCF630370AF2F00C91783 /* Flac_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Flac_Prefix.pch; sourceTree = "<group>"; };
|
||||||
|
8356BD1927B3CCBB0074E50C /* HTTPSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSource.h; path = ../HTTPSource/HTTPSource.h; sourceTree = "<group>"; };
|
||||||
8384912D180816C900E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
8384912D180816C900E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
||||||
8D5B49B6048680CD000E48DA /* Flac.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Flac.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
|
8D5B49B6048680CD000E48DA /* Flac.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Flac.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
@ -103,6 +104,7 @@
|
||||||
08FB77AFFE84173DC02AAC07 /* Classes */ = {
|
08FB77AFFE84173DC02AAC07 /* Classes */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
8356BD1927B3CCBB0074E50C /* HTTPSource.h */,
|
||||||
8384912D180816C900E7332D /* Logging.h */,
|
8384912D180816C900E7332D /* Logging.h */,
|
||||||
177FCFC10B90C9960011C3B5 /* Plugin.h */,
|
177FCFC10B90C9960011C3B5 /* Plugin.h */,
|
||||||
17C93F030B8FF67A008627D6 /* FlacDecoder.h */,
|
17C93F030B8FF67A008627D6 /* FlacDecoder.h */,
|
||||||
|
@ -274,6 +276,7 @@
|
||||||
GCC_PREFIX_HEADER = Flac_Prefix.pch;
|
GCC_PREFIX_HEADER = Flac_Prefix.pch;
|
||||||
INFOPLIST_FILE = Info.plist;
|
INFOPLIST_FILE = Info.plist;
|
||||||
INSTALL_PATH = "$(HOME)/Library/Bundles";
|
INSTALL_PATH = "$(HOME)/Library/Bundles";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.flac;
|
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.flac;
|
||||||
PRODUCT_NAME = Flac;
|
PRODUCT_NAME = Flac;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
@ -301,6 +304,7 @@
|
||||||
GCC_PREFIX_HEADER = Flac_Prefix.pch;
|
GCC_PREFIX_HEADER = Flac_Prefix.pch;
|
||||||
INFOPLIST_FILE = Info.plist;
|
INFOPLIST_FILE = Info.plist;
|
||||||
INSTALL_PATH = "$(HOME)/Library/Bundles";
|
INSTALL_PATH = "$(HOME)/Library/Bundles";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.flac;
|
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.flac;
|
||||||
PRODUCT_NAME = Flac;
|
PRODUCT_NAME = Flac;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
|
|
@ -34,6 +34,12 @@
|
||||||
|
|
||||||
BOOL hasStreamInfo;
|
BOOL hasStreamInfo;
|
||||||
BOOL streamOpened;
|
BOOL streamOpened;
|
||||||
|
BOOL abortFlag;
|
||||||
|
|
||||||
|
NSString *genre;
|
||||||
|
NSString *album;
|
||||||
|
NSString *artist;
|
||||||
|
NSString *title;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setSource:(id<CogSource>)s;
|
- (void)setSource:(id<CogSource>)s;
|
||||||
|
|
|
@ -10,30 +10,10 @@
|
||||||
|
|
||||||
#import "Logging.h"
|
#import "Logging.h"
|
||||||
|
|
||||||
|
#import "HTTPSource.h"
|
||||||
|
|
||||||
@implementation FlacDecoder
|
@implementation FlacDecoder
|
||||||
|
|
||||||
static const char *CHANNEL_MASK_TAG = "WAVEFORMATEXTENSIBLE_CHANNEL_MASK";
|
|
||||||
|
|
||||||
static FLAC__bool flac__utils_get_channel_mask_tag(const FLAC__StreamMetadata *object, FLAC__uint32 *channel_mask) {
|
|
||||||
int offset;
|
|
||||||
uint32_t val;
|
|
||||||
char *p;
|
|
||||||
FLAC__ASSERT(object);
|
|
||||||
FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
|
||||||
if(0 > (offset = FLAC__metadata_object_vorbiscomment_find_entry_from(object, /*offset=*/0, CHANNEL_MASK_TAG)))
|
|
||||||
return false;
|
|
||||||
if(object->data.vorbis_comment.comments[offset].length < strlen(CHANNEL_MASK_TAG) + 4)
|
|
||||||
return false;
|
|
||||||
if(0 == (p = strchr((const char *)object->data.vorbis_comment.comments[offset].entry, '='))) /* should never happen, but just in case */
|
|
||||||
return false;
|
|
||||||
if(strncasecmp(p, "=0x", 3))
|
|
||||||
return false;
|
|
||||||
if(sscanf(p + 3, "%x", &val) != 1)
|
|
||||||
return false;
|
|
||||||
*channel_mask = val;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder *decoder, FLAC__byte blockBuffer[], size_t *bytes, void *client_data) {
|
FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder *decoder, FLAC__byte blockBuffer[], size_t *bytes, void *client_data) {
|
||||||
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
||||||
long bytesRead = [[flacDecoder source] read:blockBuffer amount:*bytes];
|
long bytesRead = [[flacDecoder source] read:blockBuffer amount:*bytes];
|
||||||
|
@ -99,6 +79,9 @@ FLAC__StreamDecoderLengthStatus LengthCallback(const FLAC__StreamDecoder *decode
|
||||||
FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const sampleblockBuffer[], void *client_data) {
|
FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const sampleblockBuffer[], void *client_data) {
|
||||||
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
||||||
|
|
||||||
|
if(flacDecoder->abortFlag)
|
||||||
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
|
|
||||||
uint32_t channels = frame->header.channels;
|
uint32_t channels = frame->header.channels;
|
||||||
uint32_t bitsPerSample = frame->header.bits_per_sample;
|
uint32_t bitsPerSample = frame->header.bits_per_sample;
|
||||||
uint32_t frequency = frame->header.sample_rate;
|
uint32_t frequency = frame->header.sample_rate;
|
||||||
|
@ -200,7 +183,7 @@ void MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMeta
|
||||||
// to determine stream format (this seems to be consistent with flac spec: http://flac.sourceforge.net/format.html)
|
// to determine stream format (this seems to be consistent with flac spec: http://flac.sourceforge.net/format.html)
|
||||||
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
||||||
|
|
||||||
if(!flacDecoder->hasStreamInfo) {
|
if(!flacDecoder->hasStreamInfo && metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
|
||||||
flacDecoder->channels = metadata->data.stream_info.channels;
|
flacDecoder->channels = metadata->data.stream_info.channels;
|
||||||
flacDecoder->channelConfig = 0;
|
flacDecoder->channelConfig = 0;
|
||||||
flacDecoder->frequency = metadata->data.stream_info.sample_rate;
|
flacDecoder->frequency = metadata->data.stream_info.sample_rate;
|
||||||
|
@ -212,12 +195,59 @@ void MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
|
if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
|
||||||
(void)flac__utils_get_channel_mask_tag(metadata, &flacDecoder->channelConfig);
|
NSString *_genre = flacDecoder->genre;
|
||||||
|
NSString *_album = flacDecoder->album;
|
||||||
|
NSString *_artist = flacDecoder->artist;
|
||||||
|
NSString *_title = flacDecoder->title;
|
||||||
|
uint8_t nullByte = '\0';
|
||||||
|
const FLAC__StreamMetadata_VorbisComment *vorbis_comment = &metadata->data.vorbis_comment;
|
||||||
|
for(int i = 0; i < vorbis_comment->num_comments; ++i) {
|
||||||
|
NSMutableData *commentField = [NSMutableData dataWithBytes:vorbis_comment->comments[i].entry length:vorbis_comment->comments[i].length];
|
||||||
|
[commentField appendBytes:&nullByte length:1];
|
||||||
|
NSString *commentString = [NSString stringWithUTF8String:[commentField bytes]];
|
||||||
|
NSArray *splitFields = [commentString componentsSeparatedByString:@"="];
|
||||||
|
if([splitFields count] == 2) {
|
||||||
|
NSString *name = [splitFields objectAtIndex:0];
|
||||||
|
NSString *value = [splitFields objectAtIndex:1];
|
||||||
|
name = [name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
name = [name lowercaseString];
|
||||||
|
if([name isEqualToString:@"genre"]) {
|
||||||
|
_genre = value;
|
||||||
|
} else if([name isEqualToString:@"album"]) {
|
||||||
|
_album = value;
|
||||||
|
} else if([name isEqualToString:@"artist"]) {
|
||||||
|
_artist = value;
|
||||||
|
} else if([name isEqualToString:@"title"]) {
|
||||||
|
_title = value;
|
||||||
|
} else if([name isEqualToString:@"waveformatextensible_channel_mask"]) {
|
||||||
|
if([value hasPrefix:@"0x"]) {
|
||||||
|
char *end;
|
||||||
|
const char *_value = [value UTF8String] + 2;
|
||||||
|
flacDecoder->channelConfig = (uint32_t)strtoul(_value, &end, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(![_genre isEqual:flacDecoder->genre] ||
|
||||||
|
![_album isEqual:flacDecoder->album] ||
|
||||||
|
![_artist isEqual:flacDecoder->artist] ||
|
||||||
|
![_title isEqual:flacDecoder->title]) {
|
||||||
|
flacDecoder->genre = _genre;
|
||||||
|
flacDecoder->album = _album;
|
||||||
|
flacDecoder->artist = _artist;
|
||||||
|
flacDecoder->title = _title;
|
||||||
|
[flacDecoder willChangeValueForKey:@"metadata"];
|
||||||
|
[flacDecoder didChangeValueForKey:@"metadata"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) {
|
void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) {
|
||||||
// Do nothing?
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
||||||
|
if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
|
||||||
|
flacDecoder->abortFlag = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)open:(id<CogSource>)s {
|
- (BOOL)open:(id<CogSource>)s {
|
||||||
|
@ -230,11 +260,38 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS
|
||||||
[s seek:0 whence:SEEK_SET];
|
[s seek:0 whence:SEEK_SET];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must peek at stream! HTTP reader supports seeking within its buffer
|
||||||
|
BOOL isOggFlac = NO;
|
||||||
|
uint8_t buffer[4];
|
||||||
|
[s read:buffer amount:4];
|
||||||
|
[s seek:0 whence:SEEK_SET];
|
||||||
|
if(memcmp(buffer, "OggS", 4) == 0) {
|
||||||
|
isOggFlac = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
genre = @"";
|
||||||
|
album = @"";
|
||||||
|
artist = @"";
|
||||||
|
title = @"";
|
||||||
|
|
||||||
decoder = FLAC__stream_decoder_new();
|
decoder = FLAC__stream_decoder_new();
|
||||||
if(decoder == NULL)
|
if(decoder == NULL)
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
if(FLAC__stream_decoder_init_stream(decoder,
|
if(![source seekable]) {
|
||||||
|
FLAC__stream_decoder_set_md5_checking(decoder, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC__stream_decoder_set_metadata_ignore_all(decoder);
|
||||||
|
FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
|
||||||
|
FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||||
|
|
||||||
|
abortFlag = NO;
|
||||||
|
|
||||||
|
FLAC__StreamDecoderInitStatus ret;
|
||||||
|
|
||||||
|
if(isOggFlac) {
|
||||||
|
ret = FLAC__stream_decoder_init_ogg_stream(decoder,
|
||||||
ReadCallback,
|
ReadCallback,
|
||||||
([source seekable] ? SeekCallback : NULL),
|
([source seekable] ? SeekCallback : NULL),
|
||||||
([source seekable] ? TellCallback : NULL),
|
([source seekable] ? TellCallback : NULL),
|
||||||
|
@ -243,7 +300,21 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS
|
||||||
WriteCallback,
|
WriteCallback,
|
||||||
MetadataCallback,
|
MetadataCallback,
|
||||||
ErrorCallback,
|
ErrorCallback,
|
||||||
(__bridge void *)(self)) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
|
(__bridge void *)(self));
|
||||||
|
} else {
|
||||||
|
ret = FLAC__stream_decoder_init_stream(decoder,
|
||||||
|
ReadCallback,
|
||||||
|
([source seekable] ? SeekCallback : NULL),
|
||||||
|
([source seekable] ? TellCallback : NULL),
|
||||||
|
([source seekable] ? LengthCallback : NULL),
|
||||||
|
([source seekable] ? EOFCallback : NULL),
|
||||||
|
WriteCallback,
|
||||||
|
MetadataCallback,
|
||||||
|
ErrorCallback,
|
||||||
|
(__bridge void *)(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ret != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +342,9 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FLAC__stream_decoder_process_single(decoder);
|
if(!FLAC__stream_decoder_process_single(decoder)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int bytesPerFrame = ((bitsPerSample + 7) / 8) * channels;
|
int bytesPerFrame = ((bitsPerSample + 7) / 8) * channels;
|
||||||
|
@ -292,6 +365,29 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Class sourceClass = [source class];
|
||||||
|
if([sourceClass isEqual:NSClassFromString(@"HTTPSource")]) {
|
||||||
|
HTTPSource *httpSource = (HTTPSource *)source;
|
||||||
|
if([httpSource hasMetadata]) {
|
||||||
|
NSDictionary *metadata = [httpSource metadata];
|
||||||
|
NSString *_genre = [metadata valueForKey:@"genre"];
|
||||||
|
NSString *_album = [metadata valueForKey:@"album"];
|
||||||
|
NSString *_artist = [metadata valueForKey:@"artist"];
|
||||||
|
NSString *_title = [metadata valueForKey:@"title"];
|
||||||
|
if(![_genre isEqualToString:genre] ||
|
||||||
|
![_album isEqualToString:album] ||
|
||||||
|
![_artist isEqualToString:artist] ||
|
||||||
|
![_title isEqualToString:title]) {
|
||||||
|
genre = _genre;
|
||||||
|
album = _album;
|
||||||
|
artist = _artist;
|
||||||
|
title = _title;
|
||||||
|
[self willChangeValueForKey:@"metadata"];
|
||||||
|
[self didChangeValueForKey:@"metadata"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return framesRead;
|
return framesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +463,7 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *)metadata {
|
- (NSDictionary *)metadata {
|
||||||
return @{};
|
return @{ @"genre": genre, @"album": album, @"artist": artist, @"title": title };
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)fileTypes {
|
+ (NSArray *)fileTypes {
|
||||||
|
@ -375,7 +471,7 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)mimeTypes {
|
+ (NSArray *)mimeTypes {
|
||||||
return @[@"audio/x-flac"];
|
return @[@"audio/x-flac", @"application/ogg", @"audio/ogg"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (float)priority {
|
+ (float)priority {
|
||||||
|
|
|
@ -29,6 +29,11 @@
|
||||||
int bitrate;
|
int bitrate;
|
||||||
int channels;
|
int channels;
|
||||||
long totalFrames;
|
long totalFrames;
|
||||||
|
|
||||||
|
NSString *genre;
|
||||||
|
NSString *album;
|
||||||
|
NSString *artist;
|
||||||
|
NSString *title;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#import "Logging.h"
|
#import "Logging.h"
|
||||||
|
|
||||||
|
#import "HTTPSource.h"
|
||||||
|
|
||||||
@implementation OpusFile
|
@implementation OpusFile
|
||||||
|
|
||||||
static const int MAXCHANNELS = 8;
|
static const int MAXCHANNELS = 8;
|
||||||
|
@ -115,9 +117,92 @@ opus_int64 sourceTell(void *_stream) {
|
||||||
[self willChangeValueForKey:@"properties"];
|
[self willChangeValueForKey:@"properties"];
|
||||||
[self didChangeValueForKey:@"properties"];
|
[self didChangeValueForKey:@"properties"];
|
||||||
|
|
||||||
|
genre = @"";
|
||||||
|
album = @"";
|
||||||
|
artist = @"";
|
||||||
|
title = @"";
|
||||||
|
[self updateMetadata];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)updateMetadata {
|
||||||
|
const OpusTags *comment = op_tags(opusRef, -1);
|
||||||
|
|
||||||
|
if(comment) {
|
||||||
|
uint8_t nullByte = '\0';
|
||||||
|
NSString *_genre = genre;
|
||||||
|
NSString *_album = album;
|
||||||
|
NSString *_artist = artist;
|
||||||
|
NSString *_title = title;
|
||||||
|
for(int i = 0; i < comment->comments; ++i) {
|
||||||
|
NSMutableData *commentField = [NSMutableData dataWithBytes:comment->user_comments[i] length:comment->comment_lengths[i]];
|
||||||
|
[commentField appendBytes:&nullByte length:1];
|
||||||
|
NSString *commentString = [NSString stringWithUTF8String:[commentField bytes]];
|
||||||
|
NSArray *splitFields = [commentString componentsSeparatedByString:@"="];
|
||||||
|
if([splitFields count] == 2) {
|
||||||
|
NSString *name = [splitFields objectAtIndex:0];
|
||||||
|
NSString *value = [splitFields objectAtIndex:1];
|
||||||
|
name = [name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
name = [name lowercaseString];
|
||||||
|
if([name isEqualToString:@"genre"]) {
|
||||||
|
_genre = value;
|
||||||
|
} else if([name isEqualToString:@"album"]) {
|
||||||
|
_album = value;
|
||||||
|
} else if([name isEqualToString:@"artist"]) {
|
||||||
|
_artist = value;
|
||||||
|
} else if([name isEqualToString:@"title"]) {
|
||||||
|
_title = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(![_genre isEqual:genre] ||
|
||||||
|
![_album isEqual:album] ||
|
||||||
|
![_artist isEqual:artist] ||
|
||||||
|
![_title isEqual:title]) {
|
||||||
|
genre = _genre;
|
||||||
|
album = _album;
|
||||||
|
artist = _artist;
|
||||||
|
title = _title;
|
||||||
|
[self willChangeValueForKey:@"metadata"];
|
||||||
|
[self didChangeValueForKey:@"metadata"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateIcyMetadata {
|
||||||
|
NSString *_genre = genre;
|
||||||
|
NSString *_album = album;
|
||||||
|
NSString *_artist = artist;
|
||||||
|
NSString *_title = title;
|
||||||
|
|
||||||
|
Class sourceClass = [source class];
|
||||||
|
if([sourceClass isEqual:NSClassFromString(@"HTTPSource")]) {
|
||||||
|
HTTPSource *httpSource = (HTTPSource *)source;
|
||||||
|
if([httpSource hasMetadata]) {
|
||||||
|
NSDictionary *metadata = [httpSource metadata];
|
||||||
|
_genre = [metadata valueForKey:@"genre"];
|
||||||
|
_album = [metadata valueForKey:@"album"];
|
||||||
|
_artist = [metadata valueForKey:@"artist"];
|
||||||
|
_title = [metadata valueForKey:@"title"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(![_genre isEqual:genre] ||
|
||||||
|
![_album isEqual:album] ||
|
||||||
|
![_artist isEqual:artist] ||
|
||||||
|
![_title isEqual:title]) {
|
||||||
|
genre = _genre;
|
||||||
|
album = _album;
|
||||||
|
artist = _artist;
|
||||||
|
title = _title;
|
||||||
|
[self willChangeValueForKey:@"metadata"];
|
||||||
|
[self didChangeValueForKey:@"metadata"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (int)readAudio:(void *)buf frames:(UInt32)frames {
|
- (int)readAudio:(void *)buf frames:(UInt32)frames {
|
||||||
int numread;
|
int numread;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
@ -128,6 +213,8 @@ opus_int64 sourceTell(void *_stream) {
|
||||||
|
|
||||||
[self willChangeValueForKey:@"properties"];
|
[self willChangeValueForKey:@"properties"];
|
||||||
[self didChangeValueForKey:@"properties"];
|
[self didChangeValueForKey:@"properties"];
|
||||||
|
|
||||||
|
[self updateMetadata];
|
||||||
}
|
}
|
||||||
|
|
||||||
int size = frames * channels;
|
int size = frames * channels;
|
||||||
|
@ -157,6 +244,8 @@ opus_int64 sourceTell(void *_stream) {
|
||||||
|
|
||||||
} while(total != size && numread != 0);
|
} while(total != size && numread != 0);
|
||||||
|
|
||||||
|
[self updateIcyMetadata];
|
||||||
|
|
||||||
return total / channels;
|
return total / channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +278,7 @@ opus_int64 sourceTell(void *_stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *)metadata {
|
- (NSDictionary *)metadata {
|
||||||
return @{};
|
return @{ @"genre": genre, @"album": album, @"artist": artist, @"title": title };
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)fileTypes {
|
+ (NSArray *)fileTypes {
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
833F68411CDBCABC00AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
833F68411CDBCABC00AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
|
8356BD1B27B469B80074E50C /* HTTPSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSource.h; path = ../../HTTPSource/HTTPSource.h; sourceTree = "<group>"; };
|
||||||
8375B03C17FFEA400092A79F /* OpusPlugin.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpusPlugin.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
|
8375B03C17FFEA400092A79F /* OpusPlugin.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpusPlugin.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
8375B03F17FFEA400092A79F /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
8375B03F17FFEA400092A79F /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||||
8375B04217FFEA400092A79F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
8375B04217FFEA400092A79F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
|
@ -122,6 +123,7 @@
|
||||||
8375B04517FFEA400092A79F /* Opus */ = {
|
8375B04517FFEA400092A79F /* Opus */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
8356BD1B27B469B80074E50C /* HTTPSource.h */,
|
||||||
8384913718081F2700E7332D /* Logging.h */,
|
8384913718081F2700E7332D /* Logging.h */,
|
||||||
8375B36D17FFF1FE0092A79F /* Plugin.h */,
|
8375B36D17FFF1FE0092A79F /* Plugin.h */,
|
||||||
8375B36A17FFF1CB0092A79F /* OpusDecoder.h */,
|
8375B36A17FFF1CB0092A79F /* OpusDecoder.h */,
|
||||||
|
|
|
@ -31,6 +31,11 @@
|
||||||
int channels;
|
int channels;
|
||||||
float frequency;
|
float frequency;
|
||||||
long totalFrames;
|
long totalFrames;
|
||||||
|
|
||||||
|
NSString *genre;
|
||||||
|
NSString *album;
|
||||||
|
NSString *artist;
|
||||||
|
NSString *title;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#import "Logging.h"
|
#import "Logging.h"
|
||||||
|
|
||||||
|
#import "HTTPSource.h"
|
||||||
|
|
||||||
@implementation VorbisDecoder
|
@implementation VorbisDecoder
|
||||||
|
|
||||||
static const int MAXCHANNELS = 8;
|
static const int MAXCHANNELS = 8;
|
||||||
|
@ -95,9 +97,92 @@ long sourceTell(void *datasource) {
|
||||||
[self willChangeValueForKey:@"properties"];
|
[self willChangeValueForKey:@"properties"];
|
||||||
[self didChangeValueForKey:@"properties"];
|
[self didChangeValueForKey:@"properties"];
|
||||||
|
|
||||||
|
genre = @"";
|
||||||
|
album = @"";
|
||||||
|
artist = @"";
|
||||||
|
title = @"";
|
||||||
|
[self updateMetadata];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)updateMetadata {
|
||||||
|
const vorbis_comment *comment = ov_comment(&vorbisRef, -1);
|
||||||
|
|
||||||
|
if(comment) {
|
||||||
|
uint8_t nullByte = '\0';
|
||||||
|
NSString *_genre = genre;
|
||||||
|
NSString *_album = album;
|
||||||
|
NSString *_artist = artist;
|
||||||
|
NSString *_title = title;
|
||||||
|
for(int i = 0; i < comment->comments; ++i) {
|
||||||
|
NSMutableData *commentField = [NSMutableData dataWithBytes:comment->user_comments[i] length:comment->comment_lengths[i]];
|
||||||
|
[commentField appendBytes:&nullByte length:1];
|
||||||
|
NSString *commentString = [NSString stringWithUTF8String:[commentField bytes]];
|
||||||
|
NSArray *splitFields = [commentString componentsSeparatedByString:@"="];
|
||||||
|
if([splitFields count] == 2) {
|
||||||
|
NSString *name = [splitFields objectAtIndex:0];
|
||||||
|
NSString *value = [splitFields objectAtIndex:1];
|
||||||
|
name = [name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
name = [name lowercaseString];
|
||||||
|
if([name isEqualToString:@"genre"]) {
|
||||||
|
_genre = value;
|
||||||
|
} else if([name isEqualToString:@"album"]) {
|
||||||
|
_album = value;
|
||||||
|
} else if([name isEqualToString:@"artist"]) {
|
||||||
|
_artist = value;
|
||||||
|
} else if([name isEqualToString:@"title"]) {
|
||||||
|
_title = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(![_genre isEqual:genre] ||
|
||||||
|
![_album isEqual:album] ||
|
||||||
|
![_artist isEqual:artist] ||
|
||||||
|
![_title isEqual:title]) {
|
||||||
|
genre = _genre;
|
||||||
|
album = _album;
|
||||||
|
artist = _artist;
|
||||||
|
title = _title;
|
||||||
|
[self willChangeValueForKey:@"metadata"];
|
||||||
|
[self didChangeValueForKey:@"metadata"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateIcyMetadata {
|
||||||
|
NSString *_genre = genre;
|
||||||
|
NSString *_album = album;
|
||||||
|
NSString *_artist = artist;
|
||||||
|
NSString *_title = title;
|
||||||
|
|
||||||
|
Class sourceClass = [source class];
|
||||||
|
if([sourceClass isEqual:NSClassFromString(@"HTTPSource")]) {
|
||||||
|
HTTPSource *httpSource = (HTTPSource *)source;
|
||||||
|
if([httpSource hasMetadata]) {
|
||||||
|
NSDictionary *metadata = [httpSource metadata];
|
||||||
|
_genre = [metadata valueForKey:@"genre"];
|
||||||
|
_album = [metadata valueForKey:@"album"];
|
||||||
|
_artist = [metadata valueForKey:@"artist"];
|
||||||
|
_title = [metadata valueForKey:@"title"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(![_genre isEqual:genre] ||
|
||||||
|
![_album isEqual:album] ||
|
||||||
|
![_artist isEqual:artist] ||
|
||||||
|
![_title isEqual:title]) {
|
||||||
|
genre = _genre;
|
||||||
|
album = _album;
|
||||||
|
artist = _artist;
|
||||||
|
title = _title;
|
||||||
|
[self willChangeValueForKey:@"metadata"];
|
||||||
|
[self didChangeValueForKey:@"metadata"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (int)readAudio:(void *)buf frames:(UInt32)frames {
|
- (int)readAudio:(void *)buf frames:(UInt32)frames {
|
||||||
int numread;
|
int numread;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
@ -112,6 +197,8 @@ long sourceTell(void *datasource) {
|
||||||
|
|
||||||
[self willChangeValueForKey:@"properties"];
|
[self willChangeValueForKey:@"properties"];
|
||||||
[self didChangeValueForKey:@"properties"];
|
[self didChangeValueForKey:@"properties"];
|
||||||
|
|
||||||
|
[self updateMetadata];
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -141,6 +228,8 @@ long sourceTell(void *datasource) {
|
||||||
|
|
||||||
} while(total != frames && numread != 0);
|
} while(total != frames && numread != 0);
|
||||||
|
|
||||||
|
[self updateIcyMetadata];
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +261,7 @@ long sourceTell(void *datasource) {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *)metadata {
|
- (NSDictionary *)metadata {
|
||||||
return @{};
|
return @{ @"genre": genre, @"album": album, @"artist": artist, @"title": title };
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)fileTypes {
|
+ (NSArray *)fileTypes {
|
||||||
|
@ -180,7 +269,7 @@ long sourceTell(void *datasource) {
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)mimeTypes {
|
+ (NSArray *)mimeTypes {
|
||||||
return @[@"application/ogg", @"application/x-ogg", @"audio/x-vorbis+ogg"];
|
return @[@"application/ogg", @"application/x-ogg", @"audio/ogg", @"audio/x-vorbis+ogg"];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (float)priority {
|
+ (float)priority {
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
17C93D340B8FDA66008627D6 /* VorbisDecoder.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = VorbisDecoder.m; sourceTree = "<group>"; };
|
17C93D340B8FDA66008627D6 /* VorbisDecoder.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = VorbisDecoder.m; sourceTree = "<group>"; };
|
||||||
17F562EF0C3BDAAC0019975C /* Vorbis.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Vorbis.xcodeproj; path = ../../Frameworks/Vorbis/macosx/Vorbis.xcodeproj; sourceTree = SOURCE_ROOT; };
|
17F562EF0C3BDAAC0019975C /* Vorbis.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Vorbis.xcodeproj; path = ../../Frameworks/Vorbis/macosx/Vorbis.xcodeproj; sourceTree = SOURCE_ROOT; };
|
||||||
32DBCF630370AF2F00C91783 /* VorbisPlugin_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VorbisPlugin_Prefix.pch; sourceTree = "<group>"; };
|
32DBCF630370AF2F00C91783 /* VorbisPlugin_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VorbisPlugin_Prefix.pch; sourceTree = "<group>"; };
|
||||||
|
8356BD1C27B46A2D0074E50C /* HTTPSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSource.h; path = ../HTTPSource/HTTPSource.h; sourceTree = "<group>"; };
|
||||||
8384913418081A3900E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
8384913418081A3900E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
||||||
8D5B49B6048680CD000E48DA /* VorbisPlugin.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VorbisPlugin.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
|
8D5B49B6048680CD000E48DA /* VorbisPlugin.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VorbisPlugin.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
@ -111,6 +112,7 @@
|
||||||
08FB77AFFE84173DC02AAC07 /* Classes */ = {
|
08FB77AFFE84173DC02AAC07 /* Classes */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
8356BD1C27B46A2D0074E50C /* HTTPSource.h */,
|
||||||
8384913418081A3900E7332D /* Logging.h */,
|
8384913418081A3900E7332D /* Logging.h */,
|
||||||
177FCF9D0B90C9530011C3B5 /* Plugin.h */,
|
177FCF9D0B90C9530011C3B5 /* Plugin.h */,
|
||||||
17C93D330B8FDA66008627D6 /* VorbisDecoder.h */,
|
17C93D330B8FDA66008627D6 /* VorbisDecoder.h */,
|
||||||
|
|
Loading…
Reference in New Issue