├── libraries ├── config.h.in ├── vorbis.patch └── opusfile.patch ├── NFDecoder.png ├── ci ├── requirements.txt ├── ci.yaml ├── androidwindows.py ├── llvm-run.sh ├── windows.ps1 ├── README.md ├── osx.sh ├── ios.py ├── android.py ├── linux.sh ├── androidlinux.py ├── nfbuildlinux.py └── nfbuildwindows.py ├── source ├── cli │ └── CMakeLists.txt ├── Decrypter.cpp ├── LicenseManager.cpp ├── Path.h ├── base64.h ├── DataProvider.cpp ├── Decoder.cpp ├── ManifestFactory.cpp ├── LicenseManager.h ├── DecrypterFactory.cpp ├── DataProviderFactory.cpp ├── DecrypterFactoryImplementation.cpp ├── ManifestFactoryImplementation.h ├── FactoryNormalisationImplementation.h ├── ManifestFactoryImplementation.cpp ├── DecrypterFactoryImplementation.h ├── DecoderWindowsImplementation.h ├── FactoryAndroidImplementation.h ├── FactoryAppleImplementation.h ├── DataProviderFileImplementation.h ├── DataProviderMemoryImplementation.h ├── FactoryLGPLImplementation.h ├── DecoderAndroidImplementation.h ├── FactoryCommonImplementation.h ├── FactoryServiceImplementation.h ├── DataProviderFactoryImplementation.h ├── DecoderOggImplementation.h ├── FactoryServiceImplementation.cpp ├── FactoryTransmuxerImplementation.h ├── DataProviderHTTPImplementation.h ├── Path.cpp ├── DecoderNormalisationImplementation.h ├── DataProviderFileImplementation.cpp ├── FactoryNormalisationImplementation.cpp ├── DecoderSpeexImplementation.h ├── DataProviderMemoryImplementation.cpp ├── FactoryAndroidImplementation.cpp ├── FactoryAppleImplementation.cpp ├── DecoderOpusImplementation.h ├── DecoderVorbisImplementation.h ├── DecoderMidiImplementation.h ├── NFDecoderMimeTypes.cpp ├── DecoderOggImplementation.cpp ├── FactoryLGPLImplementation.cpp ├── DecoderDashToHLSTransmuxerImplementation.h ├── DecoderAudioConverterImplementation.h ├── DecoderAVCodecImplementation.h ├── base64.cpp ├── FactoryTransmuxerImplementation.cpp ├── CMakeLists.txt ├── DecoderFLACImplementation.h ├── DecoderWavImplementation.h ├── Factory.cpp └── DataProviderHTTPImplementation.cpp ├── resources └── integration-test-audio │ └── b56e61f0a5fb8e3f66bdcd511853698e.flac ├── CONTRIBUTING.md ├── .gitignore ├── .gitmodules ├── include └── NFDecoder │ ├── Manifest.h │ ├── ManifestFactory.h │ ├── DecrypterFactory.h │ ├── Decrypter.h │ ├── DataProvider.h │ ├── DataProviderFactory.h │ ├── NFDecoder.h │ ├── Decoder.h │ ├── Factory.h │ └── NFDecoderMimeTypes.h ├── tools ├── generate-version.py ├── generate-ubsan-blacklist.py ├── fix-udt-cmake.py └── generate-cli.py ├── .circleci └── config.yml └── CMakeLists.txt /libraries/config.h.in: -------------------------------------------------------------------------------- 1 | #cmakedefine HAVE_INTTYPES_H 1 2 | -------------------------------------------------------------------------------- /NFDecoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativeformat/NFDecoder/HEAD/NFDecoder.png -------------------------------------------------------------------------------- /ci/requirements.txt: -------------------------------------------------------------------------------- 1 | pyyaml 2 | flake8 3 | cmakelint 4 | pycparser 5 | pysoundfile 6 | numpy 7 | requests 8 | 9 | -------------------------------------------------------------------------------- /source/cli/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(NFDecoderCLI NFDecoderCLI.cpp) 2 | target_link_libraries(NFDecoderCLI NFDecoder) 3 | -------------------------------------------------------------------------------- /resources/integration-test-audio/b56e61f0a5fb8e3f66bdcd511853698e.flac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativeformat/NFDecoder/HEAD/resources/integration-test-audio/b56e61f0a5fb8e3f66bdcd511853698e.flac -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | Contributions are welcomed. Open a pull-request or an issue. 3 | 4 | ## Code of conduct 5 | This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to honor this code. 6 | 7 | [code-of-conduct]: https://github.com/spotify/code-of-conduct/blob/master/code-of-conduct.md 8 | -------------------------------------------------------------------------------- /ci/ci.yaml: -------------------------------------------------------------------------------- 1 | integration_tests: 2 | - audio: b56e61f0a5fb8e3f66bdcd511853698e.flac 3 | file: https://upload.wikimedia.org/wikipedia/en/4/45/ACDC_-_Back_In_Black-sample.ogg 4 | error: 0.0001 5 | offset: 0.0 6 | static_analyzer_exceptions: 7 | - source/FactoryCommonImplementation.cpp 8 | - source/FactoryCommonImplementation.h 9 | - source/FactoryTransmuxerImplementation.cpp 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Environment normalization: 2 | /.bundle 3 | /vendor/bundle 4 | 5 | # Xcode 6 | # 7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 8 | 9 | ## Build generated 10 | build/ 11 | DerivedData 12 | 13 | ## Various settings 14 | *.pbxuser 15 | !default.pbxuser 16 | *.mode1v3 17 | !default.mode1v3 18 | *.mode2v3 19 | !default.mode2v3 20 | *.perspectivev3 21 | !default.perspectivev3 22 | xcuserdata 23 | project.xcworkspace 24 | 25 | ## Other 26 | *.xccheckout 27 | *.moved-aside 28 | *.xcuserstate 29 | *.xcscmblueprint 30 | .DS_Store 31 | 32 | ## Obj-C/Swift specific 33 | *.hmap 34 | *.ipa 35 | 36 | # Carthage 37 | Carthage/Build 38 | 39 | # Ignore changes to our project.xcconfig that gets overridden by the build system 40 | project.xcconfig 41 | 42 | # Python 43 | *.egg* 44 | *.pyc 45 | nfdecoder_env 46 | -------------------------------------------------------------------------------- /ci/androidwindows.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | from nfbuildwindows import NFBuildWindows 6 | 7 | 8 | def main(): 9 | library_target = 'NFDecoder' 10 | nfbuild = NFBuildWindows() 11 | nfbuild.build_print("Installing Dependencies") 12 | nfbuild.installDependencies(android=True) 13 | # Make our main build artifacts 14 | nfbuild.build_print("C++ Build Start (x86)") 15 | nfbuild.makeBuildDirectory() 16 | nfbuild.generateProject(android=True, android_arm=False) 17 | targets = [library_target] 18 | for target in targets: 19 | nfbuild.buildTarget(target) 20 | nfbuild.build_print("C++ Build Start (arm64)") 21 | nfbuild.makeBuildDirectory() 22 | nfbuild.generateProject(android=False, android_arm=True) 23 | targets = [library_target] 24 | for target in targets: 25 | nfbuild.buildTarget(target) 26 | 27 | 28 | if __name__ == "__main__": 29 | main() 30 | -------------------------------------------------------------------------------- /ci/llvm-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Spotify AB. 3 | # 4 | # Licensed to the Apache Software Foundation (ASF) under one 5 | # or more contributor license agreements. See the NOTICE file 6 | # distributed with this work for additional information 7 | # regarding copyright ownership. The ASF licenses this file 8 | # to you under the Apache License, Version 2.0 (the 9 | # "License"); you may not use this file except in compliance 10 | # with the License. You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, 15 | # software distributed under the License is distributed on an 16 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | # KIND, either express or implied. See the License for the 18 | # specific language governing permissions and limitations 19 | # under the License. 20 | exec xcrun llvm-cov gcov "$@" 21 | -------------------------------------------------------------------------------- /source/Decrypter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include 22 | 23 | namespace nativeformat { 24 | namespace decoder { 25 | 26 | const int DECRYPTER_SUCCESS = 0; 27 | 28 | } // namespace decoder 29 | } // namespace nativeformat 30 | -------------------------------------------------------------------------------- /source/LicenseManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "LicenseManager.h" 22 | 23 | namespace nativeformat { 24 | namespace decoder { 25 | 26 | const int LICENSE_MANAGER_SUCCESS = 0; 27 | 28 | } // namespace decoder 29 | } // namespace nativeformat 30 | -------------------------------------------------------------------------------- /source/Path.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | extern bool isPathMidi(const std::string &path); 29 | extern bool isPathSoundcloud(const std::string &path); 30 | 31 | } // namespace decoder 32 | } // namespace nativeformat 33 | -------------------------------------------------------------------------------- /source/base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | base64.cpp and base64.h 3 | 4 | Copyright (C) 2004-2008 René Nyffenegger 5 | 6 | This source code is provided 'as-is', without any express or implied 7 | warranty. In no event will the author be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this source code must not be misrepresented; you must not 15 | claim that you wrote the original source code. If you use this source code 16 | in a product, an acknowledgment in the product documentation would be 17 | appreciated but is not required. 18 | 19 | 2. Altered source versions must be plainly marked as such, and must not be 20 | misrepresented as being the original source code. 21 | 22 | 3. This notice may not be removed or altered from any source distribution. 23 | 24 | René Nyffenegger rene.nyffenegger@adp-gmbh.ch 25 | 26 | */ 27 | #include 28 | 29 | std::string base64_encode(unsigned char const *, unsigned int len); 30 | std::string base64_decode(std::string const &s); 31 | -------------------------------------------------------------------------------- /source/DataProvider.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include 22 | 23 | namespace nativeformat { 24 | namespace decoder { 25 | 26 | const long UNKNOWN_SIZE = -1; 27 | const std::string DATA_PROVIDER_MEMORY_NAME("com.nativeformat.decoder.memory"); 28 | 29 | } // namespace decoder 30 | } // namespace nativeformat 31 | -------------------------------------------------------------------------------- /ci/windows.ps1: -------------------------------------------------------------------------------- 1 | Write-Host "NFDecoder build process starting..." 2 | 3 | $ErrorActionPreference = "Stop" 4 | 5 | try 6 | { 7 | # Get python version 8 | $python_version = python --version 9 | Write-Host $python_version 10 | 11 | # Start virtualenv 12 | $virtualenv_vulcan_output = python tools/vulcan/bin/vulcan.py -v -f tools/virtualenv.vulcan -p virtualenv-15.1.0 13 | $virtualenv_bin = Join-Path $virtualenv_vulcan_output /virtualenv-15.1.0/virtualenv.py 14 | python $virtualenv_bin nfdecoder_env 15 | 16 | & ./nfdecoder_env/Scripts/activate.bat 17 | 18 | # Install Python Packages 19 | & nfdecoder_env/Scripts/pip.exe install pyyaml 20 | & nfdecoder_env/Scripts/pip.exe install flake8 21 | & nfdecoder_env/Scripts/pip.exe install cmakelint 22 | & nfdecoder_env/Scripts/pip.exe install requests 23 | & nfdecoder_env/Scripts/pip.exe install pysoundfile 24 | & nfdecoder_env/Scripts/pip.exe install numpy 25 | 26 | # Install gyp 27 | cd tools/gyp 28 | & ../../nfdecoder_env/Scripts/python.exe setup.py install 29 | cd ../.. 30 | 31 | & nfdecoder_env/Scripts/python.exe ci/androidwindows.py 32 | if($LASTEXITCODE -ne 0) 33 | { 34 | exit $LASTEXITCODE 35 | } 36 | 37 | & ./nfdecoder_env/Scripts/deactivate.bat 38 | } 39 | catch 40 | { 41 | echo $_.Exception|format-list -force 42 | exit 1 43 | } 44 | -------------------------------------------------------------------------------- /source/Decoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include 22 | 23 | #include 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | const long UNKNOWN_FRAMES = -1; 29 | const std::string DECODER_AUDIOCONVERTER_NAME("com.nativeformat.decoder.audioconverter"); 30 | 31 | const std::string version() { 32 | return NFDECODER_VERSION; 33 | } 34 | 35 | } // namespace decoder 36 | } // namespace nativeformat 37 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libraries/vorbis"] 2 | path = libraries/vorbis 3 | url = https://github.com/xiph/vorbis.git 4 | [submodule "libraries/ogg"] 5 | path = libraries/ogg 6 | url = https://github.com/xiph/ogg.git 7 | [submodule "libraries/libresample"] 8 | path = libraries/libresample 9 | url = https://github.com/minorninth/libresample.git 10 | [submodule "libraries/NFHTTP"] 11 | path = libraries/NFHTTP 12 | url = https://github.com/spotify/NFHTTP.git 13 | [submodule "tools/gyp"] 14 | path = tools/gyp 15 | url = https://chromium.googlesource.com/external/gyp 16 | [submodule "libraries/opusfile"] 17 | path = libraries/opusfile 18 | url = https://github.com/xiph/opusfile 19 | [submodule "libraries/opus"] 20 | path = libraries/opus 21 | url = https://github.com/xiph/opus.git 22 | [submodule "libraries/flac"] 23 | path = libraries/flac 24 | url = https://github.com/xiph/flac.git 25 | [submodule "libraries/TinySoundFont"] 26 | path = libraries/TinySoundFont 27 | url = https://github.com/schellingb/TinySoundFont.git 28 | [submodule "libraries/universal-dash-transmuxer"] 29 | path = libraries/universal-dash-transmuxer 30 | url = https://github.com/google/universal-dash-transmuxer.git 31 | [submodule "libraries/speex"] 32 | path = libraries/speex 33 | url = https://github.com/xiph/speex.git 34 | [submodule "libraries/speexdsp"] 35 | path = libraries/speexdsp 36 | url = https://github.com/xiph/speexdsp.git 37 | -------------------------------------------------------------------------------- /source/ManifestFactory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include 22 | 23 | #include "ManifestFactoryImplementation.h" 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | std::shared_ptr createManifestFactory(std::shared_ptr client) { 29 | if (!client) { 30 | client = http::createClient(http::standardCacheLocation(), "NFDecoder"); 31 | } 32 | return std::make_shared(client); 33 | } 34 | 35 | } // namespace decoder 36 | } // namespace nativeformat 37 | -------------------------------------------------------------------------------- /source/LicenseManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | namespace nativeformat { 27 | namespace decoder { 28 | 29 | extern const int LICENSE_MANAGER_SUCCESS; 30 | 31 | class LicenseManager { 32 | public: 33 | typedef std::function 35 | LicenseURLCallback; 36 | 37 | virtual void loadLicenseURL(LicenseURLCallback callback) = 0; 38 | }; 39 | 40 | } // namespace decoder 41 | } // namespace nativeformat 42 | -------------------------------------------------------------------------------- /include/NFDecoder/Manifest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | class Manifest { 29 | public: 30 | typedef std::function LOAD_MANIFEST_CALLBACK; 31 | typedef std::function ERROR_MANIFEST_CALLBACK; 32 | 33 | virtual nlohmann::json json() = 0; 34 | virtual void load(LOAD_MANIFEST_CALLBACK load_manifest_callback, 35 | ERROR_MANIFEST_CALLBACK error_manifest_callback) = 0; 36 | }; 37 | 38 | } // namespace decoder 39 | } // namespace nativeformat 40 | -------------------------------------------------------------------------------- /source/DecrypterFactory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include 22 | 23 | #include "DecrypterFactoryImplementation.h" 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | std::shared_ptr createDecrypterFactory( 29 | std::shared_ptr client, std::shared_ptr manifest_factory) { 30 | if (!client) { 31 | client = http::createClient(http::standardCacheLocation(), "NFDecoder"); 32 | } 33 | if (!manifest_factory) { 34 | manifest_factory = createManifestFactory(client); 35 | } 36 | return std::make_shared(client, manifest_factory); 37 | } 38 | 39 | } // namespace decoder 40 | } // namespace nativeformat 41 | -------------------------------------------------------------------------------- /source/DataProviderFactory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include 22 | 23 | #include "DataProviderFactoryImplementation.h" 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | std::shared_ptr createDataProviderFactory( 29 | std::shared_ptr client, std::shared_ptr manifest_factory) { 30 | if (!client) { 31 | client = http::createClient(http::standardCacheLocation(), "NFDecoder"); 32 | } 33 | if (!manifest_factory) { 34 | manifest_factory = createManifestFactory(); 35 | } 36 | return std::make_shared(client, manifest_factory); 37 | } 38 | 39 | } // namespace decoder 40 | } // namespace nativeformat 41 | -------------------------------------------------------------------------------- /include/NFDecoder/ManifestFactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | namespace nativeformat { 30 | namespace decoder { 31 | 32 | class ManifestFactory { 33 | public: 34 | typedef std::function decrypter)> CREATE_MANIFEST_CALLBACK; 35 | 36 | virtual void createManifest(const std::string &path, 37 | const CREATE_MANIFEST_CALLBACK &create_manifest_callback, 38 | const Manifest::ERROR_MANIFEST_CALLBACK &error_manifest_callback) = 0; 39 | }; 40 | 41 | extern std::shared_ptr createManifestFactory( 42 | std::shared_ptr client = nullptr); 43 | 44 | } // namespace decoder 45 | } // namespace nativeformat 46 | -------------------------------------------------------------------------------- /source/DecrypterFactoryImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "DecrypterFactoryImplementation.h" 22 | 23 | #include "Path.h" 24 | #include "base64.h" 25 | 26 | namespace nativeformat { 27 | namespace decoder { 28 | 29 | DecrypterFactoryImplementation::DecrypterFactoryImplementation( 30 | std::shared_ptr client, std::shared_ptr manifest_factory) 31 | : _client(client), _manifest_factory(manifest_factory) {} 32 | 33 | DecrypterFactoryImplementation::~DecrypterFactoryImplementation() {} 34 | 35 | void DecrypterFactoryImplementation::createDecrypter( 36 | const std::string &path, 37 | const CREATE_DECRYPTER_CALLBACK &create_decrypter_callback, 38 | const Decrypter::ERROR_DECRYPTER_CALLBACK &error_decrypter_callback) { 39 | create_decrypter_callback(nullptr); 40 | } 41 | 42 | } // namespace decoder 43 | } // namespace nativeformat 44 | -------------------------------------------------------------------------------- /source/ManifestFactoryImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | class ManifestFactoryImplementation : public ManifestFactory { 29 | public: 30 | ManifestFactoryImplementation(std::shared_ptr &client); 31 | virtual ~ManifestFactoryImplementation(); 32 | 33 | // ManifestFactory 34 | virtual void createManifest(const std::string &path, 35 | const CREATE_MANIFEST_CALLBACK &create_manifest_callback, 36 | const Manifest::ERROR_MANIFEST_CALLBACK &error_manifest_callback); 37 | 38 | private: 39 | const std::shared_ptr _client; 40 | 41 | std::unordered_map> _manifests; 42 | }; 43 | 44 | } // namespace decoder 45 | } // namespace nativeformat 46 | -------------------------------------------------------------------------------- /include/NFDecoder/DecrypterFactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | namespace nativeformat { 31 | namespace decoder { 32 | 33 | class DecrypterFactory { 34 | public: 35 | typedef std::function decrypter)> CREATE_DECRYPTER_CALLBACK; 36 | 37 | virtual void createDecrypter( 38 | const std::string &path, 39 | const CREATE_DECRYPTER_CALLBACK &create_data_provider_callback, 40 | const Decrypter::ERROR_DECRYPTER_CALLBACK &error_data_provider_callback) = 0; 41 | }; 42 | 43 | extern std::shared_ptr createDecrypterFactory( 44 | std::shared_ptr client = nullptr, 45 | std::shared_ptr manifest_factory = nullptr); 46 | 47 | } // namespace decoder 48 | } // namespace nativeformat 49 | -------------------------------------------------------------------------------- /source/FactoryNormalisationImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | class FactoryNormalisationImplementation : public Factory { 29 | public: 30 | FactoryNormalisationImplementation(std::shared_ptr wrapped_factory); 31 | virtual ~FactoryNormalisationImplementation(); 32 | 33 | // Factory 34 | virtual void createDecoder(const std::string &path, 35 | const std::string &mime_type, 36 | const CREATE_DECODER_CALLBACK create_decoder_callback, 37 | const ERROR_DECODER_CALLBACK error_decoder_callback, 38 | double samplerate, 39 | int channels); 40 | 41 | private: 42 | std::shared_ptr _wrapped_factory; 43 | }; 44 | 45 | } // namespace decoder 46 | } // namespace nativeformat 47 | -------------------------------------------------------------------------------- /source/ManifestFactoryImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "ManifestFactoryImplementation.h" 22 | 23 | #include "Path.h" 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | ManifestFactoryImplementation::ManifestFactoryImplementation(std::shared_ptr &client) 29 | : _client(client) {} 30 | 31 | ManifestFactoryImplementation::~ManifestFactoryImplementation() {} 32 | 33 | void ManifestFactoryImplementation::createManifest( 34 | const std::string &path, 35 | const CREATE_MANIFEST_CALLBACK &create_manifest_callback, 36 | const Manifest::ERROR_MANIFEST_CALLBACK &error_manifest_callback) { 37 | auto it = _manifests.find(path); 38 | if (it != _manifests.end()) { 39 | if (auto strong_manifest = it->second.lock()) { 40 | create_manifest_callback(strong_manifest); 41 | return; 42 | } 43 | } 44 | create_manifest_callback(nullptr); 45 | } 46 | 47 | } // namespace decoder 48 | } // namespace nativeformat 49 | -------------------------------------------------------------------------------- /include/NFDecoder/Decrypter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | namespace nativeformat { 27 | namespace decoder { 28 | 29 | extern const int DECRYPTER_SUCCESS; 30 | 31 | class Decrypter { 32 | public: 33 | typedef std::function LOAD_DECRYPTER_CALLBACK; 34 | typedef std::function ERROR_DECRYPTER_CALLBACK; 35 | 36 | virtual int decrypt(const std::vector &input, 37 | std::vector &output, 38 | const unsigned char *key_id, 39 | int key_id_length, 40 | const unsigned char *iv, 41 | int iv_length) = 0; 42 | virtual void load(LOAD_DECRYPTER_CALLBACK load_decrypter_callback, 43 | ERROR_DECRYPTER_CALLBACK error_decrypter_callback) = 0; 44 | }; 45 | 46 | } // namespace decoder 47 | } // namespace nativeformat 48 | -------------------------------------------------------------------------------- /include/NFDecoder/DataProvider.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | namespace nativeformat { 27 | namespace decoder { 28 | 29 | typedef std::function LOAD_DATA_PROVIDER_CALLBACK; 30 | typedef std::function ERROR_DATA_PROVIDER_CALLBACK; 31 | 32 | extern const long UNKNOWN_SIZE; 33 | extern const std::string DATA_PROVIDER_MEMORY_NAME; 34 | 35 | class DataProvider { 36 | public: 37 | virtual size_t read(void *ptr, size_t size, size_t nmemb) = 0; 38 | virtual int seek(long offset, int whence) = 0; 39 | virtual long tell() = 0; 40 | virtual const std::string &path() = 0; 41 | virtual bool eof() = 0; 42 | virtual long size() = 0; 43 | virtual void load(const ERROR_DATA_PROVIDER_CALLBACK &data_provider_error_callback, 44 | const LOAD_DATA_PROVIDER_CALLBACK &data_provider_load_callback) = 0; 45 | virtual const std::string &name() = 0; 46 | }; 47 | 48 | } // namespace decoder 49 | } // namespace nativeformat 50 | -------------------------------------------------------------------------------- /tools/generate-version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | * Copyright (c) 2018 Spotify AB. 4 | * 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, 16 | * software distributed under the License is distributed on an 17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 | * KIND, either express or implied. See the License for the 19 | * specific language governing permissions and limitations 20 | * under the License. 21 | ''' 22 | 23 | import os 24 | import subprocess 25 | import sys 26 | 27 | 28 | def main(): 29 | output_dir = os.path.join(os.path.join('build', 'output')) 30 | if len(sys.argv) > 1: 31 | output_dir = sys.argv[1] 32 | if not os.path.exists(output_dir): 33 | os.makedirs(output_dir) 34 | print('Generating nfdecoder_generated_header.h in ' + output_dir) 35 | generated_header_filename = os.path.join(output_dir, 'nfdecoder_generated_header.h') 36 | generated_header = open(generated_header_filename, 'w') 37 | generated_header.write('// This is a generated header from generate-version.py\n') 38 | cwd = os.getcwd() 39 | git_count = subprocess.check_output(['git', 'rev-list', '--count', 'HEAD'], cwd = cwd).decode() 40 | git_describe = subprocess.check_output(['git', 'describe', '--always'], cwd = cwd).decode() 41 | generated_header.write('#define NFDECODER_VERSION "' + git_count.strip() + '-' + git_describe.strip() + '"\n') 42 | 43 | 44 | if __name__ == "__main__": 45 | main() 46 | -------------------------------------------------------------------------------- /source/DecrypterFactoryImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include "LicenseManager.h" 28 | 29 | namespace nativeformat { 30 | namespace decoder { 31 | 32 | class DecrypterFactoryImplementation 33 | : public DecrypterFactory, 34 | public std::enable_shared_from_this { 35 | public: 36 | DecrypterFactoryImplementation(std::shared_ptr client, 37 | std::shared_ptr manifest_factory); 38 | virtual ~DecrypterFactoryImplementation(); 39 | 40 | // DecrypterFactory 41 | virtual void createDecrypter( 42 | const std::string &path, 43 | const CREATE_DECRYPTER_CALLBACK &create_data_provider_callback, 44 | const Decrypter::ERROR_DECRYPTER_CALLBACK &error_data_provider_callback); 45 | 46 | private: 47 | const std::shared_ptr _client; 48 | const std::shared_ptr _manifest_factory; 49 | }; 50 | 51 | } // namespace decoder 52 | } // namespace nativeformat 53 | -------------------------------------------------------------------------------- /tools/generate-ubsan-blacklist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | * Copyright (c) 2018 Spotify AB. 4 | * 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, 16 | * software distributed under the License is distributed on an 17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 | * KIND, either express or implied. See the License for the 19 | * specific language governing permissions and limitations 20 | * under the License. 21 | ''' 22 | 23 | from __future__ import print_function 24 | 25 | import os 26 | import subprocess 27 | import sys 28 | 29 | 30 | # list of source files to blacklist for ubsan 31 | # relative to main NFDecoder project directory 32 | bad_src_list = [ 33 | 'libraries/universal-dash-transmuxer/library/dash_to_hls_api.cc', 34 | 'libraries/universal-dash-transmuxer/library/dash/dash_parser.cc' 35 | ] 36 | 37 | bad_fun_list = [ 38 | 'dash2hls::DashParser::AddSpillover', 39 | '__ZN8dash2hls10DashParser12AddSpilloverEPKhm' 40 | ] 41 | 42 | 43 | def main(): 44 | if len(sys.argv) < 2: 45 | print('Must specify path for ubsan blacklist') 46 | sys.exit(1) 47 | path_prefix = sys.argv[1] 48 | blacklist_path = os.path.join(path_prefix, 'ubsan.blacklist') 49 | 50 | with open(blacklist_path, 'w') as f: 51 | print('# Generated with %s' % sys.argv[0], file=f) 52 | print('# Do not edit directly', file=f) 53 | for src in bad_src_list: 54 | abs_path = os.path.abspath(src) 55 | print('src:%s' % abs_path, file=f) 56 | for fun in bad_fun_list: 57 | print('fun:%s' % fun, file=f) 58 | 59 | 60 | if __name__ == "__main__": 61 | main() 62 | 63 | -------------------------------------------------------------------------------- /source/DecoderWindowsImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | #pragma once 23 | #include 24 | #include 25 | #include 26 | 27 | namespace nativeformat { 28 | namespace decoder { 29 | 30 | struct decoderWindowsInternals; 31 | 32 | class DecoderWindowsImplementation 33 | : public Decoder, 34 | public std::enable_shared_from_this { 35 | public: 36 | DecoderWindowsImplementation(std::shared_ptr dataProvider); 37 | virtual ~DecoderWindowsImplementation(); 38 | 39 | virtual double sampleRate(); 40 | virtual int channels(); 41 | virtual long currentFrameIndex(); 42 | virtual void seek(long frame_index); 43 | virtual long frames(); 44 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback); 45 | virtual bool eof(); 46 | virtual const std::string &path(); 47 | virtual const std::string &name(); 48 | virtual void flush(); 49 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 50 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 51 | 52 | private: 53 | decoderWindowsInternals *internals; 54 | }; 55 | 56 | } // namespace decoder 57 | } // namespace nativeformat 58 | -------------------------------------------------------------------------------- /source/FactoryAndroidImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #if ANDROID 26 | 27 | #include 28 | 29 | namespace nativeformat { 30 | namespace decoder { 31 | 32 | class FactoryAndroidImplementation 33 | : public Factory, 34 | public std::enable_shared_from_this { 35 | public: 36 | FactoryAndroidImplementation(std::shared_ptr wrapped_factory, 37 | std::shared_ptr &data_provider_factory); 38 | virtual ~FactoryAndroidImplementation(); 39 | 40 | // Factory 41 | virtual void createDecoder(const std::string &path, 42 | const std::string &mime_type, 43 | const CREATE_DECODER_CALLBACK create_decoder_callback, 44 | const ERROR_DECODER_CALLBACK error_decoder_callback, 45 | double samplerate, 46 | int channels); 47 | 48 | private: 49 | std::shared_ptr _wrapped_factory; 50 | std::shared_ptr _data_provider_factory; 51 | }; 52 | 53 | } // namespace decoder 54 | } // namespace nativeformat 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /source/FactoryAppleImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #if __APPLE__ 26 | 27 | #include 28 | 29 | namespace nativeformat { 30 | namespace decoder { 31 | 32 | class FactoryAppleImplementation : public Factory, 33 | public std::enable_shared_from_this { 34 | public: 35 | FactoryAppleImplementation(std::shared_ptr wrapped_factory, 36 | std::shared_ptr &data_provider_factory); 37 | virtual ~FactoryAppleImplementation(); 38 | 39 | // Factory 40 | virtual void createDecoder(const std::string &path, 41 | const std::string &mime_type, 42 | const CREATE_DECODER_CALLBACK create_decoder_callback, 43 | const ERROR_DECODER_CALLBACK error_decoder_callback, 44 | double samplerate, 45 | int channels); 46 | 47 | private: 48 | std::shared_ptr _wrapped_factory; 49 | std::shared_ptr _data_provider_factory; 50 | }; 51 | 52 | } // namespace decoder 53 | } // namespace nativeformat 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /source/DataProviderFileImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | namespace nativeformat { 30 | namespace decoder { 31 | 32 | typedef std::function LOAD_DATA_PROVIDER_CALLBACK; 33 | 34 | class DataProviderFileImplementation : public DataProvider { 35 | public: 36 | typedef enum : int { ErrorCodeCouldNotReadFile } ErrorCode; 37 | 38 | DataProviderFileImplementation(const std::string &path); 39 | virtual ~DataProviderFileImplementation(); 40 | 41 | // DataProvider 42 | virtual size_t read(void *ptr, size_t size, size_t nmemb); 43 | virtual int seek(long offset, int whence); 44 | virtual long tell(); 45 | virtual const std::string &path(); 46 | virtual bool eof(); 47 | virtual long size(); 48 | virtual void load(const ERROR_DATA_PROVIDER_CALLBACK &data_provider_error_callback, 49 | const LOAD_DATA_PROVIDER_CALLBACK &data_provider_load_callback); 50 | virtual const std::string &name(); 51 | 52 | private: 53 | const std::string _path; 54 | 55 | FILE *_handle; 56 | std::atomic _size; 57 | }; 58 | 59 | } // namespace decoder 60 | } // namespace nativeformat 61 | -------------------------------------------------------------------------------- /libraries/vorbis.patch: -------------------------------------------------------------------------------- 1 | diff --git a/include/vorbis/vorbisfile.h b/include/vorbis/vorbisfile.h 2 | index 5662611..0574e64 100644 3 | --- a/include/vorbis/vorbisfile.h 4 | +++ b/include/vorbis/vorbisfile.h 5 | @@ -142,6 +142,9 @@ typedef struct OggVorbis_File { 6 | 7 | ov_callbacks callbacks; 8 | 9 | + /* The read size of the vorbis file */ 10 | + int read_size; 11 | + 12 | } OggVorbis_File; 13 | 14 | 15 | @@ -184,6 +187,7 @@ extern double ov_time_tell(OggVorbis_File *vf); 16 | 17 | extern vorbis_info *ov_info(OggVorbis_File *vf,int link); 18 | extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link); 19 | +extern void ov_set_read_size(OggVorbis_File *vf,int read_size); 20 | 21 | extern long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int samples, 22 | int *bitstream); 23 | diff --git a/lib/vorbisfile.c b/lib/vorbisfile.c 24 | index b570c3c..3e1e051 100644 25 | --- a/lib/vorbisfile.c 26 | +++ b/lib/vorbisfile.c 27 | @@ -67,8 +67,8 @@ static long _get_data(OggVorbis_File *vf){ 28 | errno=0; 29 | if(!(vf->callbacks.read_func))return(-1); 30 | if(vf->datasource){ 31 | - char *buffer=ogg_sync_buffer(&vf->oy,READSIZE); 32 | - long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource); 33 | + char *buffer=ogg_sync_buffer(&vf->oy,vf->read_size); 34 | + long bytes=(vf->callbacks.read_func)(buffer,1,vf->read_size,vf->datasource); 35 | if(bytes>0)ogg_sync_wrote(&vf->oy,bytes); 36 | if(bytes==0 && errno)return(-1); 37 | return(bytes); 38 | @@ -883,6 +883,7 @@ static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial, 39 | memset(vf,0,sizeof(*vf)); 40 | vf->datasource=f; 41 | vf->callbacks = callbacks; 42 | + vf->read_size = READSIZE; 43 | 44 | /* init the framing state */ 45 | ogg_sync_init(&vf->oy); 46 | @@ -1910,6 +1911,10 @@ vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ 47 | } 48 | } 49 | 50 | +void ov_set_read_size(OggVorbis_File *vf,int read_size) { 51 | + vf->read_size = read_size; 52 | +} 53 | + 54 | static int host_is_big_endian() { 55 | ogg_int32_t pattern = 0xfeedface; /* deadbeef */ 56 | unsigned char *bytewise = (unsigned char *)&pattern; 57 | -------------------------------------------------------------------------------- /source/DataProviderMemoryImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | namespace nativeformat { 30 | namespace decoder { 31 | 32 | class DataProviderMemoryImplementation : public DataProvider { 33 | public: 34 | typedef std::function LOAD_DATA_PROVIDER_CALLBACK; 35 | 36 | DataProviderMemoryImplementation(const std::string &path); 37 | virtual ~DataProviderMemoryImplementation(); 38 | 39 | void write(void *ptr, size_t size, size_t nmemb); 40 | void flush(); 41 | 42 | // DataProvider 43 | virtual size_t read(void *ptr, size_t size, size_t nmemb); 44 | virtual int seek(long offset, int whence); 45 | virtual long tell(); 46 | virtual const std::string &path(); 47 | virtual bool eof(); 48 | virtual long size(); 49 | virtual void load(const ERROR_DATA_PROVIDER_CALLBACK &data_provider_error_callback, 50 | const LOAD_DATA_PROVIDER_CALLBACK &data_provider_load_callback); 51 | virtual const std::string &name(); 52 | 53 | private: 54 | const std::string _path; 55 | std::mutex _data_mutex; 56 | 57 | std::vector _data; 58 | }; 59 | 60 | } // namespace decoder 61 | } // namespace nativeformat 62 | -------------------------------------------------------------------------------- /include/NFDecoder/DataProviderFactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | namespace nativeformat { 33 | namespace decoder { 34 | 35 | class DataProviderFactory { 36 | public: 37 | typedef std::function data_provider)> 38 | CREATE_DATA_PROVIDER_CALLBACK; 39 | typedef std::function(const std::string &path)> 40 | DATA_PROVIDER_CREATOR_FUNCTION; 41 | 42 | virtual void createDataProvider( 43 | const std::string &path, 44 | const CREATE_DATA_PROVIDER_CALLBACK &create_data_provider_callback, 45 | const ERROR_DATA_PROVIDER_CALLBACK &error_data_provider_callback) = 0; 46 | virtual int addDataProviderCreator( 47 | const DATA_PROVIDER_CREATOR_FUNCTION &data_provider_creator_function) = 0; 48 | virtual void removeDataProviderCreator(int creator_index) = 0; 49 | }; 50 | 51 | extern std::shared_ptr createDataProviderFactory( 52 | std::shared_ptr client = nullptr, 53 | std::shared_ptr manifest_factory = nullptr); 54 | 55 | } // namespace decoder 56 | } // namespace nativeformat 57 | -------------------------------------------------------------------------------- /include/NFDecoder/NFDecoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | namespace nativeformat { 31 | namespace decoder { 32 | 33 | typedef std::function NF_DECODER_ERROR_CALLBACK; 34 | 35 | extern const double NF_DECODER_SAMPLE_RATE_INVALID; 36 | extern const size_t NF_DECODER_CHANNELS_INVALID; 37 | 38 | /** 39 | * This is the generic interface to a decoder for obtaining the PCM samples 40 | */ 41 | class NFDecoder { 42 | public: 43 | virtual size_t write(const unsigned char *data, size_t data_size) = 0; 44 | virtual size_t read(float *samples, size_t number_of_samples) = 0; 45 | virtual size_t samples() = 0; 46 | virtual std::string mimeType() = 0; 47 | virtual size_t channels() = 0; 48 | virtual double sampleRate() = 0; 49 | virtual void flush() = 0; 50 | }; 51 | 52 | extern std::shared_ptr decoderForData( 53 | const unsigned char *data, 54 | size_t data_size, 55 | const std::string &mime_type, 56 | NF_DECODER_ERROR_CALLBACK error_callback, 57 | double sample_rate = NF_DECODER_SAMPLE_RATE_INVALID, 58 | size_t channels = NF_DECODER_CHANNELS_INVALID); 59 | 60 | } // namespace decoder 61 | } // namespace nativeformat 62 | -------------------------------------------------------------------------------- /include/NFDecoder/Decoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | namespace nativeformat { 27 | namespace decoder { 28 | 29 | typedef std::function DECODE_CALLBACK; 30 | typedef std::function LOAD_DECODER_CALLBACK; 31 | typedef std::function ERROR_DECODER_CALLBACK; 32 | 33 | extern const long UNKNOWN_FRAMES; 34 | extern const std::string DECODER_AUDIOCONVERTER_NAME; 35 | 36 | extern const std::string version(); 37 | 38 | class Decoder { 39 | public: 40 | virtual double sampleRate() = 0; 41 | virtual int channels() = 0; 42 | virtual long currentFrameIndex() = 0; 43 | virtual void seek(long frame_index) = 0; 44 | virtual long frames() = 0; 45 | virtual void decode(long frames, 46 | const DECODE_CALLBACK &decode_callback, 47 | bool synchronous = false) = 0; 48 | virtual bool eof() = 0; 49 | virtual const std::string &path() = 0; 50 | virtual const std::string &name() = 0; 51 | virtual void flush() = 0; 52 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 53 | const LOAD_DECODER_CALLBACK &decoder_load_callback) = 0; 54 | }; 55 | 56 | } // namespace decoder 57 | } // namespace nativeformat 58 | -------------------------------------------------------------------------------- /include/NFDecoder/Factory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace nativeformat { 34 | namespace decoder { 35 | 36 | typedef std::function decoder)> CREATE_DECODER_CALLBACK; 37 | 38 | extern const double STANDARD_SAMPLERATE; 39 | extern const int STANDARD_CHANNELS; 40 | 41 | class Factory { 42 | public: 43 | virtual void createDecoder(const std::string &path, 44 | const std::string &mime_type, 45 | const CREATE_DECODER_CALLBACK create_decoder_callback, 46 | const ERROR_DECODER_CALLBACK error_decoder_callback, 47 | double samplerate = STANDARD_SAMPLERATE, 48 | int channels = STANDARD_CHANNELS) = 0; 49 | }; 50 | 51 | extern std::shared_ptr createFactory( 52 | std::shared_ptr data_provider_factory = nullptr, 53 | std::shared_ptr decrypter_factory = nullptr, 54 | std::shared_ptr manifest_factory = nullptr); 55 | 56 | } // namespace decoder 57 | } // namespace nativeformat 58 | -------------------------------------------------------------------------------- /source/FactoryLGPLImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | 27 | #if INCLUDE_LGPL 28 | 29 | namespace nativeformat { 30 | namespace decoder { 31 | 32 | class FactoryLGPLImplementation : public Factory, 33 | public std::enable_shared_from_this { 34 | public: 35 | FactoryLGPLImplementation(std::shared_ptr wrapped_factory, 36 | std::shared_ptr &data_provider_factory, 37 | const std::shared_ptr &decrypter_factory); 38 | virtual ~FactoryLGPLImplementation(); 39 | 40 | // Factory 41 | virtual void createDecoder(const std::string &path, 42 | const std::string &mime_type, 43 | const CREATE_DECODER_CALLBACK create_decoder_callback, 44 | const ERROR_DECODER_CALLBACK error_decoder_callback, 45 | double samplerate, 46 | int channels); 47 | 48 | private: 49 | std::shared_ptr _wrapped_factory; 50 | std::shared_ptr _data_provider_factory; 51 | const std::shared_ptr _decrypter_factory; 52 | }; 53 | 54 | } // namespace decoder 55 | } // namespace nativeformat 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /source/DecoderAndroidImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #if ANDROID 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace nativeformat { 31 | namespace decoder { 32 | 33 | struct decoderAndroidInternals; 34 | 35 | class DecoderAndroidImplementation 36 | : public Decoder, 37 | public std::enable_shared_from_this { 38 | public: 39 | static const char *initJavaOnAppLaunch(JNIEnv *javaEnvironment, jobject activityObject); 40 | 41 | DecoderAndroidImplementation(std::shared_ptr dataProvider); 42 | virtual ~DecoderAndroidImplementation(); 43 | 44 | virtual double sampleRate(); 45 | virtual int channels(); 46 | virtual long currentFrameIndex(); 47 | virtual void seek(long frame_index); 48 | virtual long frames(); 49 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous); 50 | virtual bool eof(); 51 | virtual const std::string &path(); 52 | virtual const std::string &name(); 53 | virtual void flush(); 54 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 55 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 56 | 57 | private: 58 | decoderAndroidInternals *internals; 59 | }; 60 | 61 | } // namespace decoder 62 | } // namespace nativeformat 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /source/FactoryCommonImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | namespace nativeformat { 30 | namespace decoder { 31 | 32 | class FactoryCommonImplementation : public Factory { 33 | public: 34 | FactoryCommonImplementation(std::shared_ptr &data_provider_factory); 35 | virtual ~FactoryCommonImplementation(); 36 | 37 | // Factory 38 | virtual void createDecoder(const std::string &path, 39 | const std::string &mime_type, 40 | const CREATE_DECODER_CALLBACK create_decoder_callback, 41 | const ERROR_DECODER_CALLBACK error_decoder_callback, 42 | double samplerate, 43 | int channels); 44 | 45 | private: 46 | template 47 | static void createDecoder(std::shared_ptr data_provider, 48 | const CREATE_DECODER_CALLBACK create_decoder_callback, 49 | const ERROR_DECODER_CALLBACK error_decoder_callback); 50 | 51 | const std::shared_ptr _data_provider_factory; 52 | 53 | const std::unordered_map _extensions_to_types; 54 | }; 55 | 56 | } // namespace decoder 57 | } // namespace nativeformat 58 | -------------------------------------------------------------------------------- /source/FactoryServiceImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | 27 | namespace nativeformat { 28 | namespace decoder { 29 | 30 | class FactoryServiceImplementation 31 | : public Factory, 32 | public std::enable_shared_from_this { 33 | public: 34 | FactoryServiceImplementation(std::shared_ptr wrapped_factory, 35 | std::shared_ptr &data_provider_factory, 36 | std::shared_ptr &manifest_factory, 37 | std::shared_ptr &decrypter_factory); 38 | virtual ~FactoryServiceImplementation(); 39 | 40 | // Factory 41 | virtual void createDecoder(const std::string &path, 42 | const std::string &mime_type, 43 | const CREATE_DECODER_CALLBACK create_decoder_callback, 44 | const ERROR_DECODER_CALLBACK error_decoder_callback, 45 | double samplerate, 46 | int channels); 47 | 48 | private: 49 | std::shared_ptr _wrapped_factory; 50 | std::shared_ptr _data_provider_factory; 51 | std::shared_ptr _manifest_factory; 52 | std::shared_ptr _decrypter_factory; 53 | }; 54 | 55 | } // namespace decoder 56 | } // namespace nativeformat 57 | -------------------------------------------------------------------------------- /source/DataProviderFactoryImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | namespace nativeformat { 29 | namespace decoder { 30 | 31 | class DataProviderFactoryImplementation 32 | : public DataProviderFactory, 33 | public std::enable_shared_from_this { 34 | public: 35 | DataProviderFactoryImplementation(std::shared_ptr client, 36 | std::shared_ptr manifest_factory); 37 | virtual ~DataProviderFactoryImplementation(); 38 | 39 | static std::string domain(); 40 | 41 | // DataProviderFactory 42 | virtual void createDataProvider( 43 | const std::string &path, 44 | const CREATE_DATA_PROVIDER_CALLBACK &create_data_provider_callback, 45 | const ERROR_DATA_PROVIDER_CALLBACK &error_data_provider_callback); 46 | virtual int addDataProviderCreator( 47 | const DATA_PROVIDER_CREATOR_FUNCTION &data_provider_creator_function); 48 | virtual void removeDataProviderCreator(int creator_index); 49 | 50 | private: 51 | const std::shared_ptr _http_client; 52 | const std::shared_ptr _manifest_factory; 53 | 54 | std::mutex _creator_mutex; 55 | std::map _creator_functions; 56 | static std::atomic _creator_count; 57 | }; 58 | 59 | } // namespace decoder 60 | } // namespace nativeformat 61 | -------------------------------------------------------------------------------- /ci/README.md: -------------------------------------------------------------------------------- 1 | ## CI Build Scripts 2 | Each CI build is configured to run one of the scripts in this directory, sometimes with additional command line arguments. See the individual build configurations to view or edit the exact build pipeline commands. In general, each platform has a shell script that acts as an entry point (e.g. [osx.sh](osx.sh)) and invokes the appropriate python script (e.g. [osx.py](osx.py)). All of the platform-specific python scripts create build objects derived from [nfbuild.py](nfbuild.py). Some of the methods in the `NFBuild` python class are overriden for platform-specific functionality in the other `nfbuild*.py` files. 3 | 4 | ## Using CI Scripts Locally 5 | The ci scripts can be used to download dependencies, generate build files with CMake, compile targets, and run tests in local build environments as well. 6 | 7 | On OS X, the following commands may be useful. They all assume you have already cloned the project and all of its submodules. 8 | 9 | ### Build-in Help 10 | 11 | For a full-list of supported cmdline command, enter: 12 | 13 | ``` 14 | sh ci/osx.sh --help 15 | ``` 16 | 17 | ### Running the linter 18 | This will flag any style errors in python and CMake files, and edit C++ source files in place. It will not compile or run any targets. 19 | ``` 20 | sh ci/osx.sh lint 21 | ``` 22 | 23 | ### Running integration tests 24 | This will run the integration tests locally. 25 | If you want to skip project generation, add `-generateProject=0`. 26 | This command will not destroy the contents of your `cpp/build` folder. 27 | ``` 28 | sh ci/osx.sh local_it 29 | ``` 30 | 31 | ### Custom builds 32 | The CI scripts allow enabling/disabling any step of the build process. 33 | Options groups (or workflows) are specified without a preceding dash, and will activate a group of build steps. 34 | Additionally individual build steps can be turned on or off. For example, the command below runs the address sanitizer 35 | without wiping the build directory: 36 | ``` 37 | sh ci/osx.sh address_sanitizer -makeBuildDirectory=0 38 | ``` 39 | 40 | New build options can be added to the ci script by calling `buildOptions.addOption(optionName, optionHelpDescription)`. 41 | 42 | New workflows can be added by calling `buildOptions.addWorkflow(workflow_name, workflow_help_description, array_of_optionName)`. 43 | 44 | By convention, options should be in camel case, while workflows should use underscores. 45 | -------------------------------------------------------------------------------- /source/DecoderOggImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | namespace nativeformat { 33 | namespace decoder { 34 | 35 | typedef std::function LOAD_DECODER_CALLBACK; 36 | 37 | class DecoderOggImplementation : public Decoder, 38 | public std::enable_shared_from_this { 39 | public: 40 | typedef enum : int { ErrorCodeNotEnoughData, ErrorCodeCouldNotDecode } ErrorCode; 41 | 42 | DecoderOggImplementation(std::shared_ptr &data_provider); 43 | virtual ~DecoderOggImplementation(); 44 | 45 | // Decoder 46 | virtual double sampleRate(); 47 | virtual int channels(); 48 | virtual long currentFrameIndex(); 49 | virtual void seek(long frame_index); 50 | virtual long frames(); 51 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous); 52 | virtual bool eof(); 53 | virtual const std::string &path(); 54 | virtual const std::string &name(); 55 | virtual void flush(); 56 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 57 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 58 | 59 | private: 60 | std::shared_ptr _data_provider; 61 | std::shared_ptr _decoder; 62 | }; 63 | 64 | } // namespace decoder 65 | } // namespace nativeformat 66 | -------------------------------------------------------------------------------- /tools/fix-udt-cmake.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | * Copyright (c) 2018 Spotify AB. 4 | * 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, 16 | * software distributed under the License is distributed on an 17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 | * KIND, either express or implied. See the License for the 19 | * specific language governing permissions and limitations 20 | * under the License. 21 | ''' 22 | 23 | import fileinput 24 | import os 25 | import subprocess 26 | import sys 27 | import re 28 | 29 | def main(): 30 | if len(sys.argv) < 2: 31 | print('Missing input paths') 32 | return 33 | cmake_current_source_dir = sys.argv[1] 34 | cmakelists = os.path.join(cmake_current_source_dir, 35 | 'universal-dash-transmuxer/library/out/Default/CMakeLists.txt') 36 | print('CMAKE CURRENT SOURCE DIR: ' + cmake_current_source_dir) 37 | print('CMAKELISTS: ' + cmakelists) 38 | print(os.listdir(cmake_current_source_dir)) 39 | print(os.listdir(cmake_current_source_dir + '/universal-dash-transmuxer')) 40 | print(os.listdir(cmake_current_source_dir + '/universal-dash-transmuxer/library')) 41 | print(os.listdir(cmake_current_source_dir + '/universal-dash-transmuxer/library/out')) 42 | 43 | for line in fileinput.input(cmakelists, inplace=True, backup='.bak'): 44 | line = line.replace('USE_AVFRAMEWORK;', '') 45 | # let cmake figure out the arch 46 | line = line.replace('-arch i386', '') 47 | line = line.replace('-arch x86_64', '') 48 | line = line.replace('DashToHls_osx.pch', 49 | cmake_current_source_dir + 50 | '/universal-dash-transmuxer/library/DashToHls_osx.pch') 51 | line = line.replace('DashToHls_ios.pch', 52 | cmake_current_source_dir + 53 | '/universal-dash-transmuxer/library/DashToHls_ios.pch') 54 | if os.name == 'nt': 55 | line = line.replace('\\', '/') 56 | print(line) 57 | 58 | 59 | if __name__ == "__main__": 60 | main() 61 | -------------------------------------------------------------------------------- /source/FactoryServiceImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "FactoryServiceImplementation.h" 22 | 23 | #include "Path.h" 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | FactoryServiceImplementation::FactoryServiceImplementation( 29 | std::shared_ptr wrapped_factory, 30 | std::shared_ptr &data_provider_factory, 31 | std::shared_ptr &manifest_factory, 32 | std::shared_ptr &decrypter_factory) 33 | : _wrapped_factory(wrapped_factory), 34 | _data_provider_factory(data_provider_factory), 35 | _manifest_factory(manifest_factory), 36 | _decrypter_factory(decrypter_factory) {} 37 | 38 | FactoryServiceImplementation::~FactoryServiceImplementation() {} 39 | 40 | void FactoryServiceImplementation::createDecoder( 41 | const std::string &path, 42 | const std::string &mime_type, 43 | const CREATE_DECODER_CALLBACK create_decoder_callback, 44 | const ERROR_DECODER_CALLBACK error_decoder_callback, 45 | double samplerate, 46 | int channels) { 47 | std::string altered_mime_type = mime_type; 48 | if (isPathSoundcloud(path)) { 49 | altered_mime_type = NF_DECODER_MIME_TYPE_MP3; 50 | } 51 | _wrapped_factory->createDecoder( 52 | path, 53 | altered_mime_type, 54 | [create_decoder_callback, error_decoder_callback](std::shared_ptr decoder) { 55 | create_decoder_callback(decoder); 56 | }, 57 | error_decoder_callback, 58 | samplerate, 59 | channels); 60 | } 61 | 62 | } // namespace decoder 63 | } // namespace nativeformat 64 | -------------------------------------------------------------------------------- /source/FactoryTransmuxerImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | namespace nativeformat { 29 | namespace decoder { 30 | 31 | class FactoryTransmuxerImplementation 32 | : public Factory, 33 | public std::enable_shared_from_this { 34 | public: 35 | FactoryTransmuxerImplementation(std::shared_ptr wrapped_factory, 36 | std::shared_ptr &data_provider_factory, 37 | std::shared_ptr &manifest_factory, 38 | std::shared_ptr &decrypter_factory); 39 | virtual ~FactoryTransmuxerImplementation(); 40 | 41 | // Factory 42 | virtual void createDecoder(const std::string &path, 43 | const std::string &mime_type, 44 | const CREATE_DECODER_CALLBACK create_decoder_callback, 45 | const ERROR_DECODER_CALLBACK error_decoder_callback, 46 | double samplerate, 47 | int channels); 48 | 49 | private: 50 | std::shared_ptr _wrapped_factory; 51 | std::shared_ptr _data_provider_factory; 52 | std::shared_ptr _manifest_factory; 53 | std::shared_ptr _decrypter_factory; 54 | 55 | const std::unordered_map _extensions_to_types; 56 | }; 57 | 58 | } // namespace decoder 59 | } // namespace nativeformat 60 | -------------------------------------------------------------------------------- /source/DataProviderHTTPImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | namespace nativeformat { 35 | namespace decoder { 36 | 37 | typedef std::function LOAD_DATA_PROVIDER_CALLBACK; 38 | 39 | class DataProviderHTTPImplementation 40 | : public DataProvider, 41 | public std::enable_shared_from_this { 42 | public: 43 | typedef enum : int { ErrorCodeCouldNotReadFile } ErrorCode; 44 | 45 | DataProviderHTTPImplementation(const std::string &path, std::shared_ptr client); 46 | virtual ~DataProviderHTTPImplementation(); 47 | 48 | // DataProvider 49 | virtual size_t read(void *ptr, size_t size, size_t nmemb); 50 | virtual int seek(long offset, int whence); 51 | virtual long tell(); 52 | virtual const std::string &path(); 53 | virtual bool eof(); 54 | virtual long size(); 55 | virtual void load(const ERROR_DATA_PROVIDER_CALLBACK &data_provider_error_callback, 56 | const LOAD_DATA_PROVIDER_CALLBACK &data_provider_load_callback); 57 | virtual const std::string &name(); 58 | 59 | private: 60 | const std::string _path; 61 | 62 | std::shared_ptr _client; 63 | 64 | std::atomic _content_length; 65 | std::atomic _offset; 66 | std::mutex _read_mutex; 67 | std::future _load_future; 68 | }; 69 | 70 | } // namespace decoder 71 | } // namespace nativeformat 72 | -------------------------------------------------------------------------------- /source/Path.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "Path.h" 22 | 23 | namespace nativeformat { 24 | namespace decoder { 25 | 26 | bool isMidi(const std::string &path) { 27 | static const std::string midi_protocol = "midi:"; 28 | return path.size() > midi_protocol.size() && 29 | path.substr(0, midi_protocol.size()) == midi_protocol; 30 | } 31 | 32 | bool isPathSoundcloud(const std::string &path) { 33 | static const std::string http_protocol = "http"; 34 | static const std::string https_protocol = "https"; 35 | static const std::string protocol_separator = "://"; 36 | static const std::string soundcloud_domain = "soundcloud.com"; 37 | static const std::string soundcloud_api_domain = "api.soundcloud.com"; 38 | std::string mangled_path = path; 39 | if (mangled_path.find(http_protocol + protocol_separator) != std::string::npos) { 40 | auto length = (http_protocol + protocol_separator).length(); 41 | mangled_path = mangled_path.substr(length, mangled_path.length() - length); 42 | } else if (mangled_path.find(https_protocol + protocol_separator) != std::string::npos) { 43 | auto length = (https_protocol + protocol_separator).length(); 44 | mangled_path = mangled_path.substr(length, mangled_path.length() - length); 45 | } 46 | if ((mangled_path.length() > soundcloud_domain.length() && 47 | mangled_path.substr(0, soundcloud_domain.length()) == soundcloud_domain) || 48 | (mangled_path.length() > soundcloud_api_domain.length() && 49 | mangled_path.substr(0, soundcloud_api_domain.length()) == soundcloud_api_domain)) { 50 | return true; 51 | } 52 | return false; 53 | } 54 | 55 | } // namespace decoder 56 | } // namespace nativeformat 57 | -------------------------------------------------------------------------------- /include/NFDecoder/NFDecoderMimeTypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | namespace nativeformat { 27 | namespace decoder { 28 | 29 | // MPEG2TS 30 | extern const std::string NF_DECODER_MIME_TYPE_MP2TS; 31 | extern const std::string NF_DECODER_MIME_TYPE_VIDEO_MP2TS; 32 | extern const std::string NF_DECODER_MIME_TYPE_AUDIO_MP2TS; 33 | extern const std::set NF_DECODER_MPEG2TS_MIME_TYPES; 34 | 35 | // OGG 36 | extern const std::string NF_DECODER_MIME_TYPE_OGG; 37 | extern const std::string NF_DECODER_MIME_TYPE_AUDIO_OGG; 38 | extern const std::string NF_DECODER_MIME_TYPE_APPLICATION_OGG; 39 | extern const std::set NF_DECODER_OGG_MIME_TYPES; 40 | 41 | // WAV 42 | extern const std::string NF_DECODER_MIME_TYPE_WAV; 43 | extern const std::set NF_DECODER_WAV_MIME_TYPES; 44 | 45 | // FLAC 46 | extern const std::string NF_DECODER_MIME_TYPE_FLAC; 47 | extern const std::string NF_DECODER_MIME_TYPE_AUDIO_FLAC; 48 | extern const std::set NF_DECODER_FLAC_MIME_TYPES; 49 | 50 | // DASH 51 | extern const std::string NF_DECODER_MIME_TYPE_DASH_MP4; 52 | extern const std::set NF_DECODER_DASH_MP4_MIME_TYPES; 53 | 54 | // MP3 55 | extern const std::string NF_DECODER_MIME_TYPE_MP3; 56 | extern const std::set NF_DECODER_MP3_MIME_TYPES; 57 | 58 | // MIDI 59 | extern const std::string NF_DECODER_MIME_TYPE_MIDI; 60 | extern const std::set NF_DECODER_MIDI_MIME_TYPES; 61 | 62 | // SPEEX 63 | extern const std::string NF_DECODER_MIME_TYPE_SPEEX_OGG; 64 | extern const std::string NF_DECODER_MIME_TYPE_SPEEX; 65 | extern const std::set NF_DECODER_SPEEX_MIME_TYPES; 66 | 67 | } // namespace decoder 68 | } // namespace nativeformat 69 | -------------------------------------------------------------------------------- /source/DecoderNormalisationImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | namespace nativeformat { 36 | namespace decoder { 37 | 38 | class DecoderNormalisationImplementation 39 | : public Decoder, 40 | public std::enable_shared_from_this { 41 | public: 42 | typedef enum : int { ErrorCodeCouldNotDecodeHeader } ErrorCode; 43 | 44 | DecoderNormalisationImplementation(const std::shared_ptr &wrapped_decoder, 45 | const double samplerate, 46 | const int channels); 47 | virtual ~DecoderNormalisationImplementation(); 48 | 49 | // Decoder 50 | virtual double sampleRate(); 51 | virtual int channels(); 52 | virtual long currentFrameIndex(); 53 | virtual void seek(long frame_index); 54 | virtual long frames(); 55 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous); 56 | virtual bool eof(); 57 | virtual const std::string &path(); 58 | virtual const std::string &name(); 59 | virtual void flush(); 60 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 61 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 62 | 63 | private: 64 | const std::shared_ptr _wrapped_decoder; 65 | 66 | double _factor; 67 | void *_resampler_handlers[2]; 68 | std::atomic _frame_index; 69 | std::mutex _resampler_mutex; 70 | std::vector _pcm_buffer; 71 | std::atomic _samplerate; 72 | std::atomic_int _channels; 73 | }; 74 | 75 | } // namespace decoder 76 | } // namespace nativeformat 77 | -------------------------------------------------------------------------------- /ci/osx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Spotify AB. 3 | # 4 | # Licensed to the Apache Software Foundation (ASF) under one 5 | # or more contributor license agreements. See the NOTICE file 6 | # distributed with this work for additional information 7 | # regarding copyright ownership. The ASF licenses this file 8 | # to you under the Apache License, Version 2.0 (the 9 | # "License"); you may not use this file except in compliance 10 | # with the License. You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, 15 | # software distributed under the License is distributed on an 16 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | # KIND, either express or implied. See the License for the 18 | # specific language governing permissions and limitations 19 | # under the License. 20 | 21 | # Exit on any non-zero status 22 | 23 | # Exit on any non-zero status 24 | set -e 25 | 26 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 27 | 28 | # Homebrew on circleci consistently fails with an error like: 29 | # 30 | # ==> Checking for dependents of upgraded formulae... Error: No such file or 31 | # directory - /usr/local/Cellar/git/2.26.2_1 32 | # 33 | # Completely unpredictable, because it's just homebrew cleaning itself up and 34 | # has nothing to do with the install itself! Just continue and hope the build 35 | # fails if one of these tools is not installed. 36 | if ! HOMEBREW_NO_AUTO_UPDATE=1 brew install \ 37 | clang-format \ 38 | cmake \ 39 | ninja \ 40 | wget \ 41 | ffmpeg \ 42 | x264 \ 43 | lame \ 44 | lcov ; then 45 | echo "Homebrew install had an error, review output and try manually." 46 | fi 47 | 48 | 49 | # Update submodules 50 | git submodule sync 51 | git submodule update --init --recursive 52 | 53 | # Undo homebrew's potential meddling: https://github.com/pypa/pip/issues/5048 54 | # Homebrew will upgrade python to 3.8, but virtualenv hard codes the path to 3.7 55 | # in its shebang. 56 | pip3 uninstall --yes virtualenv && pip3 install virtualenv 57 | 58 | # Install virtualenv 59 | virtualenv --python=$(which python2) nfdecoder_env 60 | source nfdecoder_env/bin/activate 61 | 62 | # Install Python Packages 63 | pip install --upgrade six 64 | pip install --upgrade setuptools pip 65 | pip install -r ${DIR}/requirements.txt 66 | 67 | # Install gyp 68 | cd tools/gyp 69 | python setup.py install 70 | cd ../.. 71 | 72 | # Execute our python build tools 73 | if [ -n "$BUILD_IOS" ]; then 74 | python ci/ios.py "$@" 75 | else 76 | if [ -n "$BUILD_ANDROID" ]; then 77 | brew install android-ndk 78 | python ci/android.py "$@" 79 | else 80 | python ci/osx.py "$@" 81 | fi 82 | fi 83 | -------------------------------------------------------------------------------- /source/DataProviderFileImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "DataProviderFileImplementation.h" 22 | 23 | namespace nativeformat { 24 | namespace decoder { 25 | 26 | DataProviderFileImplementation::DataProviderFileImplementation(const std::string &path) 27 | : _path(path) {} 28 | 29 | DataProviderFileImplementation::~DataProviderFileImplementation() {} 30 | 31 | const std::string &DataProviderFileImplementation::name() { 32 | static const std::string domain("com.nativeformat.decoder.file"); 33 | return domain; 34 | } 35 | 36 | void DataProviderFileImplementation::load( 37 | const ERROR_DATA_PROVIDER_CALLBACK &data_provider_error_callback, 38 | const LOAD_DATA_PROVIDER_CALLBACK &data_provider_load_callback) { 39 | _handle = fopen(path().c_str(), "r"); 40 | if (!_handle) { 41 | printf("Failed to open file: %s\n", path().c_str()); 42 | data_provider_error_callback(name(), ErrorCodeCouldNotReadFile); 43 | data_provider_load_callback(false); 44 | } else { 45 | fseek(_handle, 0, SEEK_END); 46 | _size = ftell(_handle); 47 | fseek(_handle, 0, SEEK_SET); 48 | data_provider_load_callback(true); 49 | } 50 | } 51 | 52 | size_t DataProviderFileImplementation::read(void *ptr, size_t size, size_t nmemb) { 53 | size_t data_read = fread(ptr, size, nmemb, _handle); 54 | return data_read * size; 55 | } 56 | 57 | int DataProviderFileImplementation::seek(long offset, int whence) { 58 | return fseek(_handle, offset, whence); 59 | } 60 | 61 | long DataProviderFileImplementation::tell() { 62 | return ftell(_handle); 63 | } 64 | 65 | const std::string &DataProviderFileImplementation::path() { 66 | return _path; 67 | } 68 | 69 | bool DataProviderFileImplementation::eof() { 70 | return !!feof(_handle); 71 | } 72 | 73 | long DataProviderFileImplementation::size() { 74 | return _size; 75 | } 76 | 77 | } // namespace decoder 78 | } // namespace nativeformat 79 | -------------------------------------------------------------------------------- /source/FactoryNormalisationImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "FactoryNormalisationImplementation.h" 22 | 23 | #include "DecoderNormalisationImplementation.h" 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | FactoryNormalisationImplementation::FactoryNormalisationImplementation( 29 | std::shared_ptr wrapped_factory) 30 | : _wrapped_factory(wrapped_factory) {} 31 | 32 | FactoryNormalisationImplementation::~FactoryNormalisationImplementation() {} 33 | 34 | void FactoryNormalisationImplementation::createDecoder( 35 | const std::string &path, 36 | const std::string &mime_type, 37 | const CREATE_DECODER_CALLBACK create_decoder_callback, 38 | const ERROR_DECODER_CALLBACK error_decoder_callback, 39 | double samplerate, 40 | int channels) { 41 | _wrapped_factory->createDecoder( 42 | path, 43 | mime_type, 44 | [create_decoder_callback, error_decoder_callback, samplerate, channels]( 45 | std::shared_ptr decoder) { 46 | if (!decoder) { 47 | create_decoder_callback(decoder); 48 | return; 49 | } 50 | // No point in normalising an already normalised decoder 51 | if (decoder->sampleRate() == samplerate && decoder->channels() == channels) { 52 | create_decoder_callback(decoder); 53 | return; 54 | } 55 | auto normalised_decoder = 56 | std::make_shared(decoder, samplerate, channels); 57 | normalised_decoder->load(error_decoder_callback, 58 | [create_decoder_callback, normalised_decoder](bool success) { 59 | create_decoder_callback(normalised_decoder); 60 | }); 61 | }, 62 | error_decoder_callback); 63 | } 64 | 65 | } // namespace decoder 66 | } // namespace nativeformat 67 | -------------------------------------------------------------------------------- /source/DecoderSpeexImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | namespace nativeformat { 36 | namespace decoder { 37 | 38 | typedef std::function LOAD_DECODER_CALLBACK; 39 | 40 | class DecoderSpeexImplementation : public Decoder, 41 | public std::enable_shared_from_this { 42 | public: 43 | typedef enum : int { ErrorCodeNotEnoughData, ErrorCodeCouldNotDecode } ErrorCode; 44 | 45 | DecoderSpeexImplementation(std::shared_ptr &data_provider); 46 | virtual ~DecoderSpeexImplementation(); 47 | 48 | bool checkCodec(); 49 | 50 | // Decoder 51 | virtual double sampleRate(); 52 | virtual int channels(); 53 | virtual long currentFrameIndex(); 54 | virtual void seek(long frame_index); 55 | virtual long frames(); 56 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous); 57 | virtual bool eof(); 58 | virtual const std::string &path(); 59 | virtual const std::string &name(); 60 | virtual void flush(); 61 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 62 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 63 | 64 | private: 65 | std::shared_ptr _data_provider; 66 | 67 | std::mutex _speex_mutex; 68 | std::atomic _channels; 69 | std::atomic _samplerate; 70 | std::atomic _frames; 71 | std::atomic _frame_index; 72 | int _current_section; 73 | std::future _load_future; 74 | void *_state; 75 | SpeexBits _bits; 76 | std::vector _cached_samples; 77 | }; 78 | 79 | } // namespace decoder 80 | } // namespace nativeformat 81 | -------------------------------------------------------------------------------- /tools/generate-cli.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * Copyright (c) 2018 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | ''' 21 | 22 | import argparse 23 | import os 24 | import shlex 25 | import hashlib 26 | import subprocess 27 | 28 | import ffmpeg 29 | from ruamel import yaml 30 | 31 | if __name__ == '__main__': 32 | parser = argparse.ArgumentParser(description='Generate all CI CLI') 33 | parser.add_argument('cli_path', help='Path to CLI') 34 | parser.add_argument('ci_yaml', help='Path to ci.yaml') 35 | parser.add_argument('tmp_path', help='Path to cli output', default='/tmp/nf-int-output.wav') 36 | parser.add_argument('flac_dir', help='Path to flac output') 37 | args = parser.parse_args() 38 | 39 | with open(args.ci_yaml, 'r') as stream: 40 | cis = yaml.load(stream) 41 | # one of these days I'll move the rest of the script into python 42 | # for everything else there's mastercard 43 | for i in range(len(cis['integration_tests'])): 44 | ci = cis['integration_tests'][i] 45 | cli = [args.cli_path, # NFDecoder CLI 46 | ci['file'], # File to decode 47 | args.tmp_path, # Path to decoder output 48 | ci.get('offset', None), # offset 49 | ci.get('duration', None)] # duration 50 | # Remove nones 51 | cli = [str(x) for x in cli if x is not None] 52 | print(cli) 53 | subprocess.check_call(cli) 54 | md5hash = hashlib.md5(open(args.tmp_path, 'rb').read()).hexdigest() 55 | flac_file = '{md5}.flac'.format(md5=md5hash) 56 | full_flac_file = os.path.join(args.flac_dir, flac_file) 57 | ffmpeg.input(args.tmp_path).output(full_flac_file).run(overwrite_output=True) 58 | # remove tmp file because uh it helps expose errors 59 | os.remove(args.tmp_path) 60 | cis['integration_tests'][i]['audio'] = flac_file 61 | 62 | with open(os.path.join(args.flac_dir, 'ci.yaml'), 'w') as outyml: 63 | yml = yaml.YAML() 64 | yml.indent(mapping=2, sequence=4, offset=2) 65 | yml.dump(cis, outyml) 66 | 67 | -------------------------------------------------------------------------------- /source/DataProviderMemoryImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "DataProviderMemoryImplementation.h" 22 | 23 | namespace nativeformat { 24 | namespace decoder { 25 | 26 | DataProviderMemoryImplementation::DataProviderMemoryImplementation(const std::string &path) 27 | : _path(path) {} 28 | 29 | DataProviderMemoryImplementation::~DataProviderMemoryImplementation() {} 30 | 31 | const std::string &DataProviderMemoryImplementation::name() { 32 | return DATA_PROVIDER_MEMORY_NAME; 33 | } 34 | 35 | void DataProviderMemoryImplementation::write(void *ptr, size_t size, size_t nmemb) { 36 | std::lock_guard lock(_data_mutex); 37 | unsigned char *data_ptr = (unsigned char *)ptr; 38 | _data.insert(_data.end(), data_ptr, data_ptr + (size * nmemb)); 39 | } 40 | 41 | void DataProviderMemoryImplementation::flush() { 42 | std::lock_guard lock(_data_mutex); 43 | _data.clear(); 44 | } 45 | 46 | void DataProviderMemoryImplementation::load( 47 | const ERROR_DATA_PROVIDER_CALLBACK &data_provider_error_callback, 48 | const LOAD_DATA_PROVIDER_CALLBACK &data_provider_load_callback) { 49 | data_provider_load_callback(true); 50 | } 51 | 52 | size_t DataProviderMemoryImplementation::read(void *ptr, size_t size, size_t nmemb) { 53 | std::lock_guard lock(_data_mutex); 54 | size_t read_size = std::min(size * nmemb, _data.size() - (_data.size() % size)); 55 | memcpy(ptr, _data.data(), read_size); 56 | _data.erase(_data.begin(), _data.begin() + read_size); 57 | return read_size; 58 | } 59 | 60 | int DataProviderMemoryImplementation::seek(long offset, int whence) { 61 | return -1; 62 | } 63 | 64 | long DataProviderMemoryImplementation::tell() { 65 | return 0; 66 | } 67 | 68 | const std::string &DataProviderMemoryImplementation::path() { 69 | return _path; 70 | } 71 | 72 | bool DataProviderMemoryImplementation::eof() { 73 | std::lock_guard lock(_data_mutex); 74 | return _data.empty(); 75 | } 76 | 77 | long DataProviderMemoryImplementation::size() { 78 | return -1; 79 | } 80 | 81 | } // namespace decoder 82 | } // namespace nativeformat 83 | -------------------------------------------------------------------------------- /source/FactoryAndroidImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "FactoryAndroidImplementation.h" 22 | 23 | #include "DecoderAndroidImplementation.h" 24 | #include "Path.h" 25 | 26 | #if ANDROID 27 | 28 | namespace nativeformat { 29 | namespace decoder { 30 | 31 | FactoryAndroidImplementation::FactoryAndroidImplementation( 32 | std::shared_ptr wrapped_factory, 33 | std::shared_ptr &data_provider_factory) 34 | : _wrapped_factory(wrapped_factory), _data_provider_factory(data_provider_factory) {} 35 | 36 | FactoryAndroidImplementation::~FactoryAndroidImplementation() {} 37 | 38 | void FactoryAndroidImplementation::createDecoder( 39 | const std::string &path, 40 | const std::string &mime_type, 41 | const CREATE_DECODER_CALLBACK create_decoder_callback, 42 | const ERROR_DECODER_CALLBACK error_decoder_callback, 43 | double samplerate, 44 | int channels) { 45 | auto strong_this = shared_from_this(); 46 | _wrapped_factory->createDecoder( 47 | path, 48 | mime_type, 49 | [create_decoder_callback, strong_this, path, error_decoder_callback]( 50 | std::shared_ptr decoder) { 51 | if (!decoder) { 52 | strong_this->_data_provider_factory->createDataProvider( 53 | path, 54 | [create_decoder_callback, 55 | error_decoder_callback](std::shared_ptr data_provider) { 56 | if (data_provider == nullptr) { 57 | return; 58 | } 59 | auto decoder = std::make_shared(data_provider); 60 | decoder->load(error_decoder_callback, 61 | [decoder, create_decoder_callback](bool success) { 62 | create_decoder_callback(success ? decoder : nullptr); 63 | }); 64 | }, 65 | error_decoder_callback); 66 | } else { 67 | create_decoder_callback(decoder); 68 | } 69 | }, 70 | error_decoder_callback, 71 | samplerate, 72 | channels); 73 | } 74 | 75 | } // namespace decoder 76 | } // namespace nativeformat 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /source/FactoryAppleImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "FactoryAppleImplementation.h" 22 | 23 | #include "DecoderAudioConverterImplementation.h" 24 | #include "Path.h" 25 | 26 | #if __APPLE__ 27 | 28 | namespace nativeformat { 29 | namespace decoder { 30 | 31 | FactoryAppleImplementation::FactoryAppleImplementation( 32 | std::shared_ptr wrapped_factory, 33 | std::shared_ptr &data_provider_factory) 34 | : _wrapped_factory(wrapped_factory), _data_provider_factory(data_provider_factory) {} 35 | 36 | FactoryAppleImplementation::~FactoryAppleImplementation() {} 37 | 38 | void FactoryAppleImplementation::createDecoder( 39 | const std::string &path, 40 | const std::string &mime_type, 41 | const CREATE_DECODER_CALLBACK create_decoder_callback, 42 | const ERROR_DECODER_CALLBACK error_decoder_callback, 43 | double samplerate, 44 | int channels) { 45 | auto strong_this = shared_from_this(); 46 | _wrapped_factory->createDecoder( 47 | path, 48 | mime_type, 49 | [create_decoder_callback, strong_this, path, error_decoder_callback]( 50 | std::shared_ptr decoder) { 51 | if (!decoder) { 52 | strong_this->_data_provider_factory->createDataProvider( 53 | path, 54 | [create_decoder_callback, 55 | error_decoder_callback](std::shared_ptr data_provider) { 56 | if (data_provider == nullptr) { 57 | return; 58 | } 59 | auto decoder = std::make_shared(data_provider); 60 | decoder->load(error_decoder_callback, 61 | [decoder, create_decoder_callback](bool success) { 62 | create_decoder_callback(success ? decoder : nullptr); 63 | }); 64 | }, 65 | error_decoder_callback); 66 | } else { 67 | create_decoder_callback(decoder); 68 | } 69 | }, 70 | error_decoder_callback, 71 | samplerate, 72 | channels); 73 | } 74 | 75 | } // namespace decoder 76 | } // namespace nativeformat 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /source/DecoderOpusImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | extern "C" { 33 | #include 34 | } 35 | 36 | namespace nativeformat { 37 | namespace decoder { 38 | 39 | typedef std::function LOAD_DECODER_CALLBACK; 40 | 41 | class DecoderOpusImplementation : public Decoder, 42 | public std::enable_shared_from_this { 43 | public: 44 | typedef enum : int { ErrorCodeNotEnoughData, ErrorCodeCouldNotDecode } ErrorCode; 45 | 46 | DecoderOpusImplementation(std::shared_ptr &data_provider); 47 | virtual ~DecoderOpusImplementation(); 48 | 49 | bool checkCodec(); 50 | 51 | // Decoder 52 | virtual double sampleRate(); 53 | virtual int channels(); 54 | virtual long currentFrameIndex(); 55 | virtual void seek(long frame_index); 56 | virtual long frames(); 57 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous); 58 | virtual bool eof(); 59 | virtual const std::string &path(); 60 | virtual const std::string &name(); 61 | virtual void flush(); 62 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 63 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 64 | 65 | private: 66 | static int opus_read(void *datasource, unsigned char *ptr, int nbytes); 67 | static int opus_seek(void *datasource, ogg_int64_t offset, int whence); 68 | static int opus_close(void *datasource); 69 | static int64_t opus_tell(void *datasource); 70 | static std::string opus_error(int code); 71 | 72 | std::shared_ptr _data_provider; 73 | 74 | std::mutex _opus_mutex; 75 | OggOpusFile *_opus_file; 76 | std::atomic _channels; 77 | std::atomic _samplerate; 78 | std::atomic _frames; 79 | std::atomic _frame_index; 80 | int _current_section; 81 | std::future _load_future; 82 | 83 | static const OpusFileCallbacks callbacks; 84 | }; 85 | 86 | } // namespace decoder 87 | } // namespace nativeformat 88 | -------------------------------------------------------------------------------- /source/DecoderVorbisImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | extern "C" { 33 | #include 34 | } 35 | 36 | namespace nativeformat { 37 | namespace decoder { 38 | 39 | typedef std::function LOAD_DECODER_CALLBACK; 40 | 41 | class DecoderVorbisImplementation 42 | : public Decoder, 43 | public std::enable_shared_from_this { 44 | public: 45 | typedef enum : int { ErrorCodeNotEnoughData, ErrorCodeCouldNotDecode } ErrorCode; 46 | 47 | DecoderVorbisImplementation(std::shared_ptr &data_provider); 48 | virtual ~DecoderVorbisImplementation(); 49 | 50 | bool checkCodec(); 51 | 52 | // Decoder 53 | virtual double sampleRate(); 54 | virtual int channels(); 55 | virtual long currentFrameIndex(); 56 | virtual void seek(long frame_index); 57 | virtual long frames(); 58 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous); 59 | virtual bool eof(); 60 | virtual const std::string &path(); 61 | virtual const std::string &name(); 62 | virtual void flush(); 63 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 64 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 65 | 66 | private: 67 | static size_t vorbis_read(void *ptr, size_t size, size_t nmemb, void *datasource); 68 | static int vorbis_seek(void *datasource, ogg_int64_t offset, int whence); 69 | static int vorbis_close(void *datasource); 70 | static long vorbis_tell(void *datasource); 71 | static std::string vorbis_error(int code); 72 | 73 | std::shared_ptr _data_provider; 74 | 75 | std::mutex _vorbis_mutex; 76 | bool _open; 77 | vorbis_info *_info; 78 | OggVorbis_File _vorbis_file; 79 | std::atomic _channels; 80 | std::atomic _samplerate; 81 | std::atomic _frames; 82 | std::atomic _frame_index; 83 | int _current_section; 84 | std::future _load_future; 85 | 86 | static const ov_callbacks callbacks; 87 | }; 88 | 89 | } // namespace decoder 90 | } // namespace nativeformat 91 | -------------------------------------------------------------------------------- /libraries/opusfile.patch: -------------------------------------------------------------------------------- 1 | diff --git a/include/opusfile.h b/include/opusfile.h 2 | index e3a3dc8..a29621e 100644 3 | --- a/include/opusfile.h 4 | +++ b/include/opusfile.h 5 | @@ -2150,6 +2150,18 @@ OP_WARN_UNUSED_RESULT int op_read_stereo(OggOpusFile *_of, 6 | OP_WARN_UNUSED_RESULT int op_read_float_stereo(OggOpusFile *_of, 7 | float *_pcm,int _buf_size) OP_ARG_NONNULL(1); 8 | 9 | +/**Sets the read size for the \c OggOpusFile. 10 | + \param _of The \c OggOpusFile on which to set the read size. 11 | + \param _read_size The number of bytes that should be consumed each time the 12 | + \c OggOpusFile reads from its data source.*/ 13 | +void op_set_read_size(OggOpusFile *_of, int _read_size); 14 | + 15 | +/**Gets the current read size for the \c OggOpusFile. 16 | + \param _of The \c OggOpusFile on which to set the read size. 17 | + \return The number of bytes consumed each time the \c OggOpusFile 18 | + reads from its data source.*/ 19 | +int op_get_read_size(OggOpusFile *_of); 20 | + 21 | /*@}*/ 22 | /*@}*/ 23 | 24 | diff --git a/src/internal.h b/src/internal.h 25 | index 9ac17e0..1fd0319 100644 26 | --- a/src/internal.h 27 | +++ b/src/internal.h 28 | @@ -251,6 +251,8 @@ struct OggOpusFile{ 29 | occurs (switching between the float/short APIs, or between the 30 | stereo/multistream APIs).*/ 31 | int state_channel_count; 32 | + /*The read size for the opus file in bytes*/ 33 | + int read_size; 34 | #endif 35 | }; 36 | 37 | diff --git a/src/opusfile.c b/src/opusfile.c 38 | index 72f1272..7fa7d0c 100644 39 | --- a/src/opusfile.c 40 | +++ b/src/opusfile.c 41 | @@ -197,12 +197,12 @@ static opus_int64 op_get_next_page(OggOpusFile *_of,ogg_page *_og, 42 | int ret; 43 | /*Send more paramedics.*/ 44 | if(!_boundary)return OP_FALSE; 45 | - if(_boundary<0)read_nbytes=OP_READ_SIZE; 46 | + if(_boundary<0)read_nbytes=_of->read_size; 47 | else{ 48 | opus_int64 position; 49 | position=op_position(_of); 50 | if(position>=_boundary)return OP_FALSE; 51 | - read_nbytes=(int)OP_MIN(_boundary-position,OP_READ_SIZE); 52 | + read_nbytes=(int)OP_MIN(_boundary-position,_of->read_size); 53 | } 54 | ret=op_get_data(_of,read_nbytes); 55 | if(OP_UNLIKELY(ret<0))return OP_EREAD; 56 | @@ -1513,6 +1513,7 @@ static int op_open1(OggOpusFile *_of, 57 | _of->end=-1; 58 | _of->stream=_stream; 59 | *&_of->callbacks=*_cb; 60 | + _of->read_size = OP_READ_SIZE; 61 | /*At a minimum, we need to be able to read data.*/ 62 | if(OP_UNLIKELY(_of->callbacks.read==NULL))return OP_EREAD; 63 | /*Initialize the framing state.*/ 64 | @@ -3320,4 +3321,14 @@ int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){ 65 | return op_filter_read_native(_of,_pcm,_buf_size,op_stereo_filter,NULL); 66 | } 67 | 68 | +void op_set_read_size(OggOpusFile *_of, int _read_size) { 69 | + _read_size = _read_size > OP_CHUNK_SIZE_MAX ? OP_CHUNK_SIZE_MAX : _read_size; 70 | + _read_size = _read_size < 1 ? OP_READ_SIZE : _read_size; 71 | + _of->read_size = _read_size; 72 | +} 73 | + 74 | +int op_get_read_size(OggOpusFile *_of) { 75 | + return _of->read_size; 76 | +} 77 | + 78 | #endif 79 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | buildlinuxclang: 4 | docker: 5 | - image: ubuntu:bionic 6 | steps: 7 | - checkout 8 | - run: 9 | name: Build Linux with clang 10 | command: USE_CURL=1 sh ci/linux.sh clang_build 11 | - store_artifacts: 12 | path: build/output/libNFDecoder.zip 13 | destination: libNFDecoder.zip 14 | buildlinuxgcc: 15 | docker: 16 | - image: ubuntu:bionic 17 | steps: 18 | - checkout 19 | - run: 20 | name: Build Linux with gcc 21 | command: USE_CURL=1 sh ci/linux.sh gcc_build 22 | - store_artifacts: 23 | path: build/output/libNFDecoder.zip 24 | destination: libNFDecoder.zip 25 | buildlinuxandroid: 26 | docker: 27 | - image: ubuntu:bionic 28 | steps: 29 | - checkout 30 | - run: 31 | name: Build Android 32 | command: BUILD_ANDROID=1 USE_CURL=1 sh ci/linux.sh build 33 | - store_artifacts: 34 | path: libNFDecoder-androidx86.zip 35 | destination: libNFDecoder-androidx86.zip 36 | - store_artifacts: 37 | path: libNFDecoder-androidArm64.zip 38 | destination: libNFDecoder-androidArm64.zip 39 | buildmac: 40 | macos: 41 | xcode: "11.5.0" 42 | environment: 43 | HOMEBREW_NO_AUTO_UPDATE: 1 44 | steps: 45 | - checkout 46 | - run: brew update 47 | - run: git submodule sync 48 | - run: git submodule update --init --recursive 49 | - run: 50 | name: Build OSX 51 | command: USE_CURL=1 sh ci/osx.sh build 52 | - store_artifacts: 53 | path: build/output/libNFDecoder.zip 54 | destination: libNFDecoder.zip 55 | buildmacios: 56 | macos: 57 | xcode: "11.5.0" 58 | environment: 59 | HOMEBREW_NO_AUTO_UPDATE: 1 60 | steps: 61 | - checkout 62 | - run: brew update 63 | - run: git submodule sync 64 | - run: git submodule update --init --recursive 65 | - run: 66 | name: Build iOS 67 | command: BUILD_IOS=1 USE_CURL=1 sh ci/osx.sh build 68 | - store_artifacts: 69 | path: build/output/libNFDecoder.zip 70 | destination: libNFDecoder.zip 71 | buildmacandroid: 72 | macos: 73 | xcode: "11.5.0" 74 | environment: 75 | HOMEBREW_NO_AUTO_UPDATE: 1 76 | steps: 77 | - checkout 78 | - run: brew update 79 | - run: git submodule sync 80 | - run: git submodule update --init --recursive 81 | # Android NDK does not pass. 82 | - run: sudo spctl --master-disable 83 | - run: 84 | name: Build Android 85 | command: BUILD_ANDROID=1 USE_CURL=1 sh ci/osx.sh build 86 | - store_artifacts: 87 | path: libNFDecoder-androidx86.zip 88 | destination: libNFDecoder-androidx86.zip 89 | - store_artifacts: 90 | path: libNFDecoder-androidArm64.zip 91 | destination: libNFDecoder-androidArm64.zip 92 | workflows: 93 | version: 2 94 | build: 95 | jobs: 96 | - buildlinuxclang 97 | - buildlinuxgcc 98 | - buildlinuxandroid 99 | - buildmac 100 | - buildmacios 101 | - buildmacandroid 102 | -------------------------------------------------------------------------------- /source/DecoderMidiImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #define TSF_STATIC 30 | #define TSF_IMPLEMENTATION 31 | #include 32 | #undef TSF_IMPLEMENTATION 33 | #undef TSF_STATIC 34 | 35 | #define TML_STATIC 36 | #define TML_IMPLEMENTATION 37 | #include 38 | #undef TML_IMPLEMENTATION 39 | #undef TML_STATIC 40 | 41 | namespace nativeformat { 42 | namespace decoder { 43 | 44 | class DecoderMidiImplementation : public Decoder, 45 | public std::enable_shared_from_this { 46 | public: 47 | enum class ErrorCode : int { ErrorCodeLoadMIDIFailure, ErrorCodeLoadSoundFontFailure }; 48 | 49 | DecoderMidiImplementation(const std::string &path); 50 | ~DecoderMidiImplementation(); 51 | 52 | virtual double sampleRate() final; 53 | virtual int channels() final; 54 | virtual long currentFrameIndex() final; 55 | virtual void seek(long frame_index) final; 56 | virtual long frames() final; 57 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous) final; 58 | virtual bool eof() final; 59 | virtual const std::string &path() final; 60 | virtual const std::string &name() final; 61 | virtual void flush() final; 62 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 63 | const LOAD_DECODER_CALLBACK &decoder_load_callback) final; 64 | 65 | const tml_message *stream() { return _midi_stream; } 66 | const tsf *soundbank() { return _soundfont; } 67 | 68 | void load_midi(); 69 | void load_soundfont(); 70 | 71 | private: 72 | std::string midi_prefix = "midi:"; 73 | std::string soundfont_prefix = ":soundfont:"; 74 | 75 | std::string _midi_path; 76 | std::string _soundfont_path; 77 | // TODO: Replace _midi_stream and _soundfont with custom allocators 78 | // makes it easier on the destructor 79 | // TODO: If the midi seeking becomes to slow consider copying the midi data 80 | // into a vector and freeing the file 81 | tml_message *_midi_head; 82 | tml_message *_midi_stream; 83 | tsf *_soundfont; 84 | 85 | std::atomic _channels; 86 | std::atomic _samplerate; 87 | std::atomic _frame_size; 88 | std::atomic _frame_index; 89 | std::atomic _frames; 90 | std::future _load_future; 91 | }; 92 | 93 | } // namespace decoder 94 | } // namespace nativeformat 95 | -------------------------------------------------------------------------------- /source/NFDecoderMimeTypes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include 22 | 23 | namespace nativeformat { 24 | namespace decoder { 25 | 26 | const std::string NF_DECODER_MIME_TYPE_MP2TS("mp2ts"); 27 | const std::string NF_DECODER_MIME_TYPE_VIDEO_MP2TS("video/mp2ts"); 28 | const std::string NF_DECODER_MIME_TYPE_AUDIO_MP2TS("audio/mp2ts"); 29 | const std::set NF_DECODER_MPEG2TS_MIME_TYPES({NF_DECODER_MIME_TYPE_MP2TS, 30 | NF_DECODER_MIME_TYPE_VIDEO_MP2TS, 31 | NF_DECODER_MIME_TYPE_AUDIO_MP2TS}); 32 | 33 | const std::string NF_DECODER_MIME_TYPE_OGG("ogg"); 34 | const std::string NF_DECODER_MIME_TYPE_AUDIO_OGG("audio/ogg"); 35 | const std::string NF_DECODER_MIME_TYPE_APPLICATION_OGG("application/ogg"); 36 | const std::set NF_DECODER_OGG_MIME_TYPES({NF_DECODER_MIME_TYPE_OGG, 37 | NF_DECODER_MIME_TYPE_AUDIO_OGG, 38 | NF_DECODER_MIME_TYPE_APPLICATION_OGG}); 39 | 40 | const std::string NF_DECODER_MIME_TYPE_WAV("audio/wav"); 41 | const std::set NF_DECODER_WAV_MIME_TYPES( 42 | {NF_DECODER_MIME_TYPE_WAV, "audio/x-wav", "audio/wave", "audio/x-pn-wave"}); 43 | 44 | const std::string NF_DECODER_MIME_TYPE_FLAC("flac"); 45 | const std::string NF_DECODER_MIME_TYPE_AUDIO_FLAC("audio/flac"); 46 | const std::set NF_DECODER_FLAC_MIME_TYPES({NF_DECODER_MIME_TYPE_FLAC, 47 | NF_DECODER_MIME_TYPE_AUDIO_FLAC}); 48 | 49 | const std::string NF_DECODER_MIME_TYPE_DASH_MP4("dash/mp4"); 50 | const std::set NF_DECODER_DASH_MP4_MIME_TYPES({NF_DECODER_MIME_TYPE_DASH_MP4}); 51 | 52 | const std::string NF_DECODER_MIME_TYPE_MP3("audio/mpeg"); 53 | const std::set NF_DECODER_MP3_MIME_TYPES({NF_DECODER_MIME_TYPE_MP3}); 54 | 55 | const std::string NF_DECODER_MIME_TYPE_MIDI("midi"); 56 | const std::set NF_DECODER_MIDI_MIME_TYPES({NF_DECODER_MIME_TYPE_MIDI}); 57 | 58 | const std::string NF_DECODER_MIME_TYPE_SPEEX_OGG("audio/x-speex"); 59 | extern const std::string NF_DECODER_MIME_TYPE_SPEEX("audio/speex"); 60 | extern const std::set NF_DECODER_SPEEX_MIME_TYPES({NF_DECODER_MIME_TYPE_SPEEX_OGG, 61 | NF_DECODER_MIME_TYPE_SPEEX}); 62 | 63 | } // namespace decoder 64 | } // namespace nativeformat 65 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(NFDecoder) 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_FLAGS 7 | "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") 8 | set(CMAKE_CXX_FLAGS 9 | "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedefs") 10 | if(LLVM_STDLIB) 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ \ 12 | -Wno-tautological-undefined-compare -Wno-shorten-64-to-32") 13 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 14 | else() 15 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") 16 | endif() 17 | set(CMAKE_MODULE_PATH 18 | ${CMAKE_MODULE_PATH} 19 | ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules) 20 | 21 | if(DEFINED CMAKE_BUILD_TYPE) 22 | set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING 23 | "Choose the type of build: None, Debug, or Release" 24 | FORCE) 25 | else() 26 | set(CMAKE_BUILD_TYPE Debug CACHE STRING 27 | "Choose the type of build: None, Debug, or Release" 28 | FORCE) 29 | endif() 30 | 31 | if(INCLUDE_LGPL) 32 | add_definitions(-DINCLUDE_LGPL=1) 33 | message("Including LGPL code") 34 | endif() 35 | 36 | if(USE_UB_SANITIZER) 37 | message("Using Undefined Behavior Sanitizer") 38 | execute_process(COMMAND python 39 | tools/generate-ubsan-blacklist.py "${CMAKE_CURRENT_SOURCE_DIR}/tools" 40 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") 41 | set(UB_SAN_BLACKLIST "${CMAKE_CURRENT_SOURCE_DIR}/tools/ubsan.blacklist") 42 | execute_process(COMMAND cat "${UB_SAN_BLACKLIST}" 43 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") 44 | set(UB_SAN_FLAGS " -g -fsanitize=undefined -fno-omit-frame-pointer") 45 | set(UB_SAN_FLAGS "${UB_SAN_FLAGS} -fno-sanitize-recover=all") 46 | set(UB_SAN_FLAGS "${UB_SAN_FLAGS} -fsanitize-blacklist=${UB_SAN_BLACKLIST}") 47 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${UB_SAN_FLAGS}") 48 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${UB_SAN_FLAGS}") 49 | endif() 50 | 51 | if(USE_MEM_SANITIZER AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux") 52 | # This isn't really helpful since we have too many 53 | # dependencies that aren't compiled from source 54 | message("Using Memory Sanitizer") 55 | set(MEM_SAN_FLAGS " -g -fsanitize=memory -fno-omit-frame-pointer") 56 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MEM_SAN_FLAGS}") 57 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MEM_SAN_FLAGS}") 58 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lc++abi") 59 | endif() 60 | 61 | if(USE_ADDRESS_SANITIZER) 62 | message("Using Address & Leak Sanitizer") 63 | set( 64 | CMAKE_CXX_FLAGS 65 | "${CMAKE_CXX_FLAGS} -fsanitize=address -g -fno-omit-frame-pointer") 66 | set( 67 | CMAKE_EXE_LINKER_FLAGS 68 | "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address -g -fno-omit-frame-pointer") 69 | endif() 70 | 71 | if(CODE_COVERAGE) 72 | message("Using Code Coverage") 73 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") 74 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") 75 | endif() 76 | 77 | if(IOS) 78 | message("Building a project for iOS") 79 | set(CMAKE_XCODE_ATTRIBUTE_SDKROOT iphoneos) 80 | set(CMAKE_XCODE_SUPPORTED_PLATFORMS "iphonesimulator iphoneos") 81 | endif() 82 | 83 | execute_process(COMMAND python 84 | "${CMAKE_CURRENT_SOURCE_DIR}/tools/generate-version.py" 85 | ${CMAKE_BINARY_DIR}/output 86 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 87 | 88 | add_subdirectory(libraries) 89 | add_subdirectory(source) 90 | -------------------------------------------------------------------------------- /ci/ios.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | * Copyright (c) 2018 Spotify AB. 4 | * 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, 16 | * software distributed under the License is distributed on an 17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 | * KIND, either express or implied. See the License for the 19 | * specific language governing permissions and limitations 20 | * under the License. 21 | ''' 22 | 23 | import sys 24 | 25 | from nfbuildosx import NFBuildOSX 26 | 27 | from build_options import BuildOptions 28 | 29 | 30 | def main(): 31 | buildOptions = BuildOptions() 32 | buildOptions.addOption("installDependencies", "Install dependencies") 33 | buildOptions.addOption("lintCmake", "Lint cmake files") 34 | buildOptions.addOption("lintCpp", "Lint CPP Files") 35 | buildOptions.addOption("lintCppWithInlineChange", 36 | "Lint CPP Files and fix them") 37 | buildOptions.addOption("makeBuildDirectory", 38 | "Wipe existing build directory") 39 | buildOptions.addOption("generateProject", "Regenerate xcode project") 40 | buildOptions.addOption("buildTargetIphoneSimulator", 41 | "Build Target: iPhone Simulator") 42 | buildOptions.addOption("buildTargetIphoneOS", "Build Target: iPhone OS") 43 | 44 | buildOptions.setDefaultWorkflow("Empty workflow", []) 45 | 46 | buildOptions.addWorkflow("lint", "Run lint workflow", [ 47 | 'installDependencies', 48 | 'lintCmake', 49 | 'lintCppWithInlineChange' 50 | ]) 51 | 52 | buildOptions.addWorkflow("build", "Production Build", [ 53 | 'installDependencies', 54 | 'lintCmake', 55 | 'lintCpp', 56 | 'makeBuildDirectory', 57 | 'generateProject', 58 | 'buildTargetIphoneSimulator', 59 | 'buildTargetIphoneOS', 60 | ]) 61 | 62 | options = buildOptions.parseArgs() 63 | buildOptions.verbosePrintBuildOptions(options) 64 | 65 | library_target = 'NFDecoder' 66 | nfbuild = NFBuildOSX() 67 | 68 | if buildOptions.checkOption(options, 'installDependencies'): 69 | nfbuild.installDependencies() 70 | 71 | if buildOptions.checkOption(options, 'lintCmake'): 72 | nfbuild.lintCmake() 73 | 74 | if buildOptions.checkOption(options, 'lintCppWithInlineChange'): 75 | nfbuild.lintCPP(make_inline_changes=True) 76 | elif buildOptions.checkOption(options, 'lintCpp'): 77 | nfbuild.lintCPP(make_inline_changes=False) 78 | 79 | if buildOptions.checkOption(options, 'makeBuildDirectory'): 80 | nfbuild.makeBuildDirectory() 81 | 82 | if buildOptions.checkOption(options, 'generateProject'): 83 | nfbuild.generateProject(ios=True) 84 | 85 | if buildOptions.checkOption(options, 'buildTargetIphoneSimulator'): 86 | nfbuild.buildTarget(library_target, 87 | sdk='iphonesimulator', 88 | arch='x86_64') 89 | 90 | if buildOptions.checkOption(options, 'buildTargetIphoneOS'): 91 | nfbuild.buildTarget(library_target, sdk='iphoneos', arch='arm64') 92 | 93 | if __name__ == "__main__": 94 | main() 95 | -------------------------------------------------------------------------------- /source/DecoderOggImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "DecoderOggImplementation.h" 22 | #include "DecoderOpusImplementation.h" 23 | #include "DecoderVorbisImplementation.h" 24 | 25 | #include 26 | #include 27 | 28 | namespace nativeformat { 29 | namespace decoder { 30 | 31 | DecoderOggImplementation::DecoderOggImplementation(std::shared_ptr &data_provider) 32 | : _data_provider(data_provider), _decoder(nullptr) {} 33 | 34 | DecoderOggImplementation::~DecoderOggImplementation() {} 35 | 36 | const std::string &DecoderOggImplementation::name() { 37 | static const std::string domain("com.nativeformat.decoder.ogg"); 38 | return domain; 39 | } 40 | 41 | void DecoderOggImplementation::load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 42 | const LOAD_DECODER_CALLBACK &decoder_load_callback) { 43 | // Try both vorbis and opus decoders 44 | auto vorbisDecoder = std::make_shared(_data_provider); 45 | if (vorbisDecoder.get()->checkCodec()) { 46 | _decoder = vorbisDecoder; 47 | _decoder->load(decoder_error_callback, decoder_load_callback); 48 | return; 49 | } 50 | 51 | _data_provider->seek(0, SEEK_SET); 52 | auto opusDecoder = std::make_shared(_data_provider); 53 | if (opusDecoder.get()->checkCodec()) { 54 | _decoder = opusDecoder; 55 | _decoder->load(decoder_error_callback, decoder_load_callback); 56 | return; 57 | } 58 | 59 | decoder_error_callback(name(), ErrorCodeCouldNotDecode); 60 | decoder_load_callback(false); 61 | } 62 | 63 | double DecoderOggImplementation::sampleRate() { 64 | return _decoder->sampleRate(); 65 | } 66 | 67 | int DecoderOggImplementation::channels() { 68 | return _decoder->channels(); 69 | } 70 | 71 | long DecoderOggImplementation::currentFrameIndex() { 72 | return _decoder->currentFrameIndex(); 73 | } 74 | 75 | void DecoderOggImplementation::seek(long frame_index) { 76 | _decoder->seek(frame_index); 77 | } 78 | 79 | long DecoderOggImplementation::frames() { 80 | return _decoder->frames(); 81 | } 82 | 83 | void DecoderOggImplementation::decode(long frames, 84 | const DECODE_CALLBACK &decode_callback, 85 | bool synchronous) { 86 | _decoder->decode(frames, decode_callback, synchronous); 87 | } 88 | 89 | bool DecoderOggImplementation::eof() { 90 | return _decoder->eof(); 91 | } 92 | 93 | const std::string &DecoderOggImplementation::path() { 94 | return _data_provider->path(); 95 | } 96 | 97 | void DecoderOggImplementation::flush() { 98 | _decoder->flush(); 99 | } 100 | 101 | } // namespace decoder 102 | } // namespace nativeformat 103 | -------------------------------------------------------------------------------- /source/FactoryLGPLImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "FactoryLGPLImplementation.h" 22 | 23 | #if INCLUDE_LGPL 24 | 25 | #include "DecoderAVCodecImplementation.h" 26 | #include "Path.h" 27 | 28 | namespace nativeformat { 29 | namespace decoder { 30 | 31 | FactoryLGPLImplementation::FactoryLGPLImplementation( 32 | std::shared_ptr wrapped_factory, 33 | std::shared_ptr &data_provider_factory, 34 | const std::shared_ptr &decrypter_factory) 35 | : _wrapped_factory(wrapped_factory), 36 | _data_provider_factory(data_provider_factory), 37 | _decrypter_factory(decrypter_factory) {} 38 | 39 | FactoryLGPLImplementation::~FactoryLGPLImplementation() {} 40 | 41 | void FactoryLGPLImplementation::createDecoder(const std::string &path, 42 | const std::string &mime_type, 43 | const CREATE_DECODER_CALLBACK create_decoder_callback, 44 | const ERROR_DECODER_CALLBACK error_decoder_callback, 45 | double samplerate, 46 | int channels) { 47 | auto strong_this = shared_from_this(); 48 | _wrapped_factory->createDecoder( 49 | path, 50 | mime_type, 51 | [create_decoder_callback, strong_this, path, error_decoder_callback]( 52 | std::shared_ptr decoder) { 53 | if (!decoder) { 54 | strong_this->_decrypter_factory->createDecrypter( 55 | path, 56 | [strong_this, create_decoder_callback, error_decoder_callback, path]( 57 | const std::shared_ptr &decrypter) { 58 | strong_this->_data_provider_factory->createDataProvider( 59 | path, 60 | [create_decoder_callback, error_decoder_callback, decrypter]( 61 | const std::shared_ptr &data_provider) { 62 | auto decoder = 63 | std::make_shared(data_provider, decrypter); 64 | decoder->load(error_decoder_callback, 65 | [decoder, create_decoder_callback](bool success) { 66 | create_decoder_callback(success ? decoder : nullptr); 67 | }); 68 | }, 69 | error_decoder_callback); 70 | }, 71 | error_decoder_callback); 72 | } else { 73 | create_decoder_callback(decoder); 74 | } 75 | }, 76 | error_decoder_callback, 77 | samplerate, 78 | channels); 79 | } 80 | 81 | } // namespace decoder 82 | } // namespace nativeformat 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /ci/android.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | * Copyright (c) 2018 Spotify AB. 4 | * 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, 16 | * software distributed under the License is distributed on an 17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 | * KIND, either express or implied. See the License for the 19 | * specific language governing permissions and limitations 20 | * under the License. 21 | ''' 22 | 23 | import sys 24 | 25 | from nfbuildosx import NFBuildOSX 26 | from build_options import BuildOptions 27 | 28 | 29 | def main(): 30 | buildOptions = BuildOptions() 31 | buildOptions.addOption("makeBuildDirectoryX86", 32 | "Wipe existing build directory for X86 build.") 33 | buildOptions.addOption("generateProjectX86", "Regenerate project for X86 build") 34 | 35 | buildOptions.addOption("buildTargetLibraryX86", "Build Target: Library (X86)") 36 | 37 | buildOptions.addOption("makeBuildDirectoryArm64", 38 | "Wipe existing build directory for ARM64 build.") 39 | buildOptions.addOption("generateProjectArm64", "Regenerate project for ARM64 build") 40 | # buildOptions.addOption("packageArtifacts", "Package the artifacts produced by the build") 41 | buildOptions.addOption("buildTargetLibraryArm64", "Build Target: Library (ARM64)") 42 | 43 | buildOptions.setDefaultWorkflow("Empty workflow", []) 44 | 45 | buildOptions.addWorkflow("build", "Production Build (Android OSX)", [ 46 | 'makeBuildDirectoryX86', 47 | 'generateProjectX86', 48 | 'buildTargetLibraryX86', 49 | 'makeBuildDirectoryArm64', 50 | 'generateProjectArm64', 51 | 'buildTargetLibraryArm64', 52 | ]) 53 | 54 | buildOptions.addWorkflow("buildX86", "Production Build (X86)", [ 55 | 'makeBuildDirectoryX86', 56 | 'generateProjectX86', 57 | 'buildTargetLibraryX86', 58 | ]) 59 | 60 | buildOptions.addWorkflow("buildArm64", "Production Build (ARM64)", [ 61 | 'makeBuildDirectoryArm64', 62 | 'generateProjectArm64', 63 | 'buildTargetLibraryArm64', 64 | ]) 65 | 66 | options = buildOptions.parseArgs() 67 | buildOptions.verbosePrintBuildOptions(options) 68 | 69 | library_target = 'NFDecoder' 70 | nfbuild = NFBuildOSX() 71 | 72 | if buildOptions.checkOption(options, 'makeBuildDirectoryX86'): 73 | nfbuild.makeBuildDirectory() 74 | 75 | if buildOptions.checkOption(options, 'generateProjectX86'): 76 | nfbuild.generateProject(android=True, android_arm=False) 77 | 78 | if buildOptions.checkOption(options, 'buildTargetLibraryX86'): 79 | nfbuild.buildTarget(library_target) 80 | 81 | # if buildOptions.checkOption(options, 'packageArtifacts'): 82 | # nfbuild.packageArtifacts() 83 | 84 | if buildOptions.checkOption(options, 'makeBuildDirectoryArm64'): 85 | nfbuild.makeBuildDirectory() 86 | 87 | if buildOptions.checkOption(options, 'generateProjectArm64'): 88 | nfbuild.generateProject(android=True, android_arm=True) 89 | 90 | if buildOptions.checkOption(options, 'buildTargetLibraryArm64'): 91 | nfbuild.buildTarget(library_target) 92 | 93 | 94 | if __name__ == "__main__": 95 | main() 96 | -------------------------------------------------------------------------------- /ci/linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2018 Spotify AB. 3 | # 4 | # Licensed to the Apache Software Foundation (ASF) under one 5 | # or more contributor license agreements. See the NOTICE file 6 | # distributed with this work for additional information 7 | # regarding copyright ownership. The ASF licenses this file 8 | # to you under the Apache License, Version 2.0 (the 9 | # "License"); you may not use this file except in compliance 10 | # with the License. You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, 15 | # software distributed under the License is distributed on an 16 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | # KIND, either express or implied. See the License for the 18 | # specific language governing permissions and limitations 19 | # under the License. 20 | 21 | # Exit on any non-zero status 22 | set -e 23 | set -x 24 | 25 | # DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 26 | 27 | # Install system dependencies 28 | apt-get -q update 29 | apt-get install sudo 30 | sudo apt-get install -y -q --no-install-recommends software-properties-common 31 | # sudo add-apt-repository -y ppa:mc3man/trusty-media 32 | sudo apt-get -q update 33 | sudo apt-get install -y -q --no-install-recommends apt-utils \ 34 | ninja-build \ 35 | clang \ 36 | clang-format \ 37 | libc++-dev \ 38 | libcurl4-openssl-dev \ 39 | libssl-dev \ 40 | libc++-dev \ 41 | wget \ 42 | libsndfile1 \ 43 | git \ 44 | unzip \ 45 | make \ 46 | libyaml-dev \ 47 | libssl-dev \ 48 | python-dev \ 49 | python3-dev \ 50 | python-virtualenv \ 51 | build-essential \ 52 | autoconf \ 53 | libtool \ 54 | libffi-dev \ 55 | libffi6 \ 56 | libblas3 \ 57 | libblas-dev \ 58 | liblapack3 \ 59 | liblapack-dev \ 60 | libatlas3-base \ 61 | libatlas-base-dev \ 62 | x264 \ 63 | lame \ 64 | python-pip \ 65 | virtualenv \ 66 | cmake \ 67 | libidn11 \ 68 | libidn11-dev \ 69 | libavformat-dev \ 70 | libavcodec-dev \ 71 | libavutil-dev \ 72 | libswscale-dev \ 73 | libavresample-dev \ 74 | libavfilter-dev \ 75 | libavdevice-dev \ 76 | libavcodec-extra \ 77 | libc++abi-dev \ 78 | libc++-dev \ 79 | libboost-all-dev \ 80 | gobjc++ \ 81 | ffmpeg \ 82 | llvm 83 | 84 | # Update submodules 85 | git submodule sync 86 | git submodule update --init --recursive 87 | 88 | export CC=clang 89 | export CXX=clang++ 90 | 91 | # Install boost 1.64.x 92 | #wget --no-check-certificate https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.bz2 -O boost_1_64_0.tar.bz2 93 | #tar --bzip2 -xf boost_1_64_0.tar.bz2 94 | #export BOOST_ROOT="$PWD/boost_1_64_0" 95 | 96 | # Install virtualenv 97 | virtualenv --python=$(which python2) nfdecoder_env 98 | . nfdecoder_env/bin/activate 99 | 100 | # Install Python Packages 101 | pip install six 102 | # pip install --upgrade setuptools pip 103 | pip install -r ${PWD}/ci/requirements.txt 104 | 105 | # Install gyp 106 | cd tools/gyp 107 | python setup.py install 108 | cd ../.. 109 | 110 | # Execute our python build tools 111 | if [ -n "$BUILD_ANDROID" ]; then 112 | # Install Android NDK 113 | NDK='android-ndk-r17b-linux-x86_64' 114 | ZIP='zip' 115 | wget https://dl.google.com/android/repository/${NDK}.${ZIP} -O ${PWD}/${NDK}.${ZIP} 116 | unzip -o -q ${NDK}.${ZIP} 117 | rm -rf ~/ndk 118 | mv android-ndk-r17b ~/ndk 119 | 120 | chmod +x -R ~/ndk 121 | 122 | python ci/androidlinux.py "$@" 123 | else 124 | python ci/linux.py "$@" 125 | fi 126 | -------------------------------------------------------------------------------- /source/DecoderDashToHLSTransmuxerImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #if INCLUDE_UDT 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | #include "DataProviderMemoryImplementation.h" 40 | 41 | namespace nativeformat { 42 | namespace decoder { 43 | 44 | class DecoderDashToHLSTransmuxerImplementation 45 | : public Decoder, 46 | public std::enable_shared_from_this { 47 | public: 48 | typedef std::function EXHAUST_CALLBACK; 49 | 50 | DecoderDashToHLSTransmuxerImplementation( 51 | const std::shared_ptr &data_provider, 52 | const std::shared_ptr &data_provider_factory, 53 | const std::string &path, 54 | const std::shared_ptr &factory, 55 | const std::shared_ptr &manifest, 56 | const std::shared_ptr &decrypter); 57 | virtual ~DecoderDashToHLSTransmuxerImplementation(); 58 | 59 | // Decoder 60 | virtual double sampleRate(); 61 | virtual int channels(); 62 | virtual long currentFrameIndex(); 63 | virtual void seek(long frame_index); 64 | virtual long frames(); 65 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous); 66 | virtual bool eof(); 67 | virtual const std::string &path(); 68 | virtual const std::string &name(); 69 | virtual void flush(); 70 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 71 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 72 | virtual std::string fake_path(); 73 | 74 | private: 75 | void loadSegment(int segment_index, 76 | const ERROR_DECODER_CALLBACK &decoder_error_callback, 77 | const EXHAUST_CALLBACK &exhaust_callback); 78 | DashToHlsStatus writeSegment(int segment_index); 79 | void exhaustDecoder(int segment_index, const EXHAUST_CALLBACK &exhaust_callback); 80 | 81 | static std::atomic _next; 82 | long _id; 83 | 84 | const std::shared_ptr _data_provider; 85 | const std::shared_ptr _data_provider_factory; 86 | const std::shared_ptr _factory; 87 | const std::shared_ptr _manifest; 88 | const std::shared_ptr _decrypter; 89 | 90 | const std::shared_ptr _data_provider_memory; 91 | 92 | DashToHlsSession *_session; 93 | DashToHlsIndex *_index; 94 | std::shared_ptr _decoder; 95 | std::atomic _frame_index; 96 | std::vector _samples; 97 | std::mutex _decoding_mutex; 98 | long _start_junk_frames; 99 | }; 100 | 101 | } // namespace decoder 102 | } // namespace nativeformat 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /ci/androidlinux.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | * Copyright (c) 2018 Spotify AB. 4 | * 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, 16 | * software distributed under the License is distributed on an 17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 | * KIND, either express or implied. See the License for the 19 | * specific language governing permissions and limitations 20 | * under the License. 21 | ''' 22 | 23 | import sys 24 | 25 | from nfbuildlinux import NFBuildLinux 26 | from build_options import BuildOptions 27 | 28 | 29 | def main(): 30 | buildOptions = BuildOptions() 31 | 32 | buildOptions.addOption("makeBuildDirectoryX86", 33 | "Wipe existing build directory for X86 build.") 34 | buildOptions.addOption("generateProjectX86", "Regenerate project for X86 build") 35 | 36 | buildOptions.addOption("buildTargetLibraryX86", "Build Target: Library (X86)") 37 | 38 | buildOptions.addOption("makeBuildDirectoryArm64", 39 | "Wipe existing build directory for ARM64 build.") 40 | buildOptions.addOption("generateProjectArm64", "Regenerate project for ARM64 build") 41 | # buildOptions.addOption("packageArtifacts", "Package the artifacts produced by the build") 42 | buildOptions.addOption("buildTargetLibraryArm64", "Build Target: Library (ARM64)") 43 | 44 | buildOptions.setDefaultWorkflow("Empty workflow", []) 45 | 46 | buildOptions.addWorkflow("build", "Production Build (Android Linux)", [ 47 | 'makeBuildDirectoryX86', 48 | 'generateProjectX86', 49 | 'buildTargetLibraryX86', 50 | 'makeBuildDirectoryArm64', 51 | 'generateProjectArm64', 52 | 'buildTargetLibraryArm64', 53 | ]) 54 | 55 | buildOptions.addWorkflow("buildX86", "Production Build (X86)", [ 56 | 'makeBuildDirectoryX86', 57 | 'generateProjectX86', 58 | 'buildTargetLibraryX86', 59 | ]) 60 | 61 | buildOptions.addWorkflow("buildArm64", "Production Build (ARM64)", [ 62 | 'makeBuildDirectoryArm64', 63 | 'generateProjectArm64', 64 | 'buildTargetLibraryArm64', 65 | ]) 66 | 67 | options = buildOptions.parseArgs() 68 | buildOptions.verbosePrintBuildOptions(options) 69 | 70 | library_target = 'NFDecoder' 71 | nfbuild = NFBuildLinux() 72 | 73 | if buildOptions.checkOption(options, 'makeBuildDirectoryX86'): 74 | nfbuild.makeBuildDirectory() 75 | 76 | if buildOptions.checkOption(options, 'generateProjectX86'): 77 | nfbuild.generateProject(android=True, android_arm=False) 78 | 79 | if buildOptions.checkOption(options, 'buildTargetLibraryX86'): 80 | nfbuild.buildTarget(library_target) 81 | 82 | # if buildOptions.checkOption(options, 'packageArtifacts'): 83 | # nfbuild.packageArtifacts() 84 | 85 | if buildOptions.checkOption(options, 'makeBuildDirectoryArm64'): 86 | nfbuild.makeBuildDirectory() 87 | 88 | if buildOptions.checkOption(options, 'generateProjectArm64'): 89 | nfbuild.generateProject(android=True, android_arm=True) 90 | 91 | if buildOptions.checkOption(options, 'buildTargetLibraryArm64'): 92 | nfbuild.buildTarget(library_target) 93 | 94 | # if buildOptions.checkOption(options, 'packageArtifacts'): 95 | # nfbuild.packageArtifacts() 96 | 97 | 98 | if __name__ == "__main__": 99 | main() 100 | -------------------------------------------------------------------------------- /source/DecoderAudioConverterImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #if __APPLE__ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | #import 36 | 37 | namespace nativeformat { 38 | namespace decoder { 39 | 40 | class DecoderAudioConverterImplementation 41 | : public Decoder, 42 | public std::enable_shared_from_this { 43 | public: 44 | typedef enum : int { ErrorCodeNotEnoughDataForHeader, ErrorCodeCouldNotDecodeHeader } ErrorCode; 45 | 46 | DecoderAudioConverterImplementation(std::shared_ptr &data_provider); 47 | virtual ~DecoderAudioConverterImplementation(); 48 | 49 | // Decoder 50 | virtual double sampleRate(); 51 | virtual int channels(); 52 | virtual long currentFrameIndex(); 53 | virtual void seek(long frame_index); 54 | virtual long frames(); 55 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous); 56 | virtual bool eof(); 57 | virtual const std::string &path(); 58 | virtual const std::string &name(); 59 | virtual void flush(); 60 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 61 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 62 | 63 | private: 64 | static void listenerProc(void *inClientData, 65 | AudioFileStreamID inAudioFileStream, 66 | AudioFileStreamPropertyID inPropertyID, 67 | AudioFileStreamPropertyFlags *ioFlags); 68 | static void sampleProc(void *inClientData, 69 | UInt32 inNumberBytes, 70 | UInt32 inNumberPackets, 71 | const void *inInputData, 72 | AudioStreamPacketDescription *inPacketDescriptions); 73 | static OSStatus inputDataProc(AudioConverterRef inAudioConverter, 74 | UInt32 *ioNumberDataPackets, 75 | AudioBufferList *ioData, 76 | AudioStreamPacketDescription **outDataPacketDescription, 77 | void *inUserData); 78 | 79 | std::shared_ptr _data_provider; 80 | 81 | std::future _load_future; 82 | AudioFileStreamID _audio_file_stream; 83 | std::atomic _audio_converter_setup_complete; 84 | AudioConverterRef _audio_converter; 85 | std::atomic _channels; 86 | std::atomic _samplerate; 87 | AudioStreamBasicDescription _output_format; 88 | AudioBuffer _input_buffer; 89 | UInt32 _input_packets; 90 | AudioStreamPacketDescription *_packet_descriptions; 91 | std::atomic _frame_index; 92 | std::mutex _audiotoolbox_mutex; 93 | std::atomic _frames; 94 | long _frame_offset; 95 | std::vector _pcm_buffer; 96 | long _start_junk_frames; 97 | }; 98 | 99 | } // namespace decoder 100 | } // namespace nativeformat 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /source/DecoderAVCodecImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #if INCLUDE_LGPL 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | extern "C" { 37 | #include 38 | #include 39 | #include 40 | #include 41 | } 42 | 43 | namespace nativeformat { 44 | namespace decoder { 45 | 46 | extern const std::string DECODER_AVCODEC_NAME; 47 | 48 | class DecoderAVCodecImplementation 49 | : public Decoder, 50 | public std::enable_shared_from_this { 51 | public: 52 | typedef enum : int { ErrorCodeCouldNotDecodeHeader } ErrorCode; 53 | 54 | DecoderAVCodecImplementation(const std::shared_ptr &data_provider, 55 | const std::shared_ptr &decrypter); 56 | virtual ~DecoderAVCodecImplementation(); 57 | 58 | // Decoder 59 | virtual double sampleRate(); 60 | virtual int channels(); 61 | virtual long currentFrameIndex(); 62 | virtual void seek(long frame_index); 63 | virtual long frames(); 64 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous); 65 | virtual bool eof(); 66 | virtual const std::string &path(); 67 | virtual const std::string &name(); 68 | virtual void flush(); 69 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 70 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 71 | 72 | private: 73 | #pragma pack(push, 1) 74 | typedef struct SIDX_FRAME { 75 | uint32_t junk; 76 | uint32_t subsegment_duration; 77 | uint32_t referenced_size; 78 | } SIDX_FRAME; 79 | #pragma pack(pop) 80 | struct MOOFS { 81 | MOOFS() : offset(0) {} 82 | int offset; 83 | std::vector _sidx_frames; 84 | }; 85 | virtual void runDecodeThread(long frames, const DECODE_CALLBACK &decode_callback); 86 | static int avio_read(void *opaque, uint8_t *buf, int buf_size); 87 | static int64_t avio_seek(void *opaque, int64_t offset, int whence); 88 | 89 | int moofIndex(size_t byte_offset); 90 | 91 | std::shared_ptr _data_provider; 92 | const std::shared_ptr _decrypter; 93 | 94 | std::future _load_future; 95 | std::atomic _frame_index; 96 | std::atomic _frames; 97 | unsigned char *_io_context_buffer; 98 | AVIOContext *_io_context; 99 | AVFormatContext *_format_context; 100 | AVAudioResampleContext *_resample_context; 101 | AVCodecContext *_codec_context; 102 | std::mutex _av_mutex; 103 | std::vector _pcm_buffer; 104 | unsigned char *_key_id; 105 | size_t _key_id_length; 106 | AVStream *_stream; 107 | int _start_junk_frames; 108 | long _frames_per_entry_index; 109 | bool _found_sidx; 110 | std::map _ivs; 111 | MOOFS _moofs; 112 | long _packets_per_moof; 113 | }; 114 | 115 | } // namespace decoder 116 | } // namespace nativeformat 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /source/base64.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | base64.cpp and base64.h 3 | 4 | Copyright (C) 2004-2008 René Nyffenegger 5 | 6 | This source code is provided 'as-is', without any express or implied 7 | warranty. In no event will the author be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this source code must not be misrepresented; you must not 15 | claim that you wrote the original source code. If you use this source code 16 | in a product, an acknowledgment in the product documentation would be 17 | appreciated but is not required. 18 | 19 | 2. Altered source versions must be plainly marked as such, and must not be 20 | misrepresented as being the original source code. 21 | 22 | 3. This notice may not be removed or altered from any source distribution. 23 | 24 | René Nyffenegger rene.nyffenegger@adp-gmbh.ch 25 | 26 | */ 27 | 28 | #include "base64.h" 29 | #include 30 | 31 | static const std::string base64_chars = 32 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 33 | "abcdefghijklmnopqrstuvwxyz" 34 | "0123456789+/"; 35 | 36 | static inline bool is_base64(unsigned char c) { 37 | return (isalnum(c) || (c == '+') || (c == '/')); 38 | } 39 | 40 | std::string base64_encode(unsigned char const *bytes_to_encode, unsigned int in_len) { 41 | std::string ret; 42 | int i = 0; 43 | int j = 0; 44 | unsigned char char_array_3[3]; 45 | unsigned char char_array_4[4]; 46 | 47 | while (in_len--) { 48 | char_array_3[i++] = *(bytes_to_encode++); 49 | if (i == 3) { 50 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 51 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 52 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 53 | char_array_4[3] = char_array_3[2] & 0x3f; 54 | 55 | for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]]; 56 | i = 0; 57 | } 58 | } 59 | 60 | if (i) { 61 | for (j = i; j < 3; j++) char_array_3[j] = '\0'; 62 | 63 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 64 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 65 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 66 | char_array_4[3] = char_array_3[2] & 0x3f; 67 | 68 | for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]]; 69 | 70 | while ((i++ < 3)) ret += '='; 71 | } 72 | 73 | return ret; 74 | } 75 | 76 | std::string base64_decode(std::string const &encoded_string) { 77 | int in_len = encoded_string.size(); 78 | int i = 0; 79 | int j = 0; 80 | int in_ = 0; 81 | unsigned char char_array_4[4], char_array_3[3]; 82 | std::string ret; 83 | 84 | while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { 85 | char_array_4[i++] = encoded_string[in_]; 86 | in_++; 87 | if (i == 4) { 88 | for (i = 0; i < 4; i++) char_array_4[i] = base64_chars.find(char_array_4[i]); 89 | 90 | char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); 91 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 92 | char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; 93 | 94 | for (i = 0; (i < 3); i++) ret += char_array_3[i]; 95 | i = 0; 96 | } 97 | } 98 | 99 | if (i) { 100 | for (j = i; j < 4; j++) char_array_4[j] = 0; 101 | 102 | for (j = 0; j < 4; j++) char_array_4[j] = base64_chars.find(char_array_4[j]); 103 | 104 | char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); 105 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 106 | char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; 107 | 108 | for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; 109 | } 110 | 111 | return ret; 112 | } 113 | -------------------------------------------------------------------------------- /ci/nfbuildlinux.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | * Copyright (c) 2018 Spotify AB. 4 | * 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, 16 | * software distributed under the License is distributed on an 17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 | * KIND, either express or implied. See the License for the 19 | * specific language governing permissions and limitations 20 | * under the License. 21 | ''' 22 | 23 | import fnmatch 24 | import os 25 | import plistlib 26 | import re 27 | import shutil 28 | import subprocess 29 | import sys 30 | 31 | from distutils import dir_util 32 | from nfbuild import NFBuild 33 | 34 | 35 | class NFBuildLinux(NFBuild): 36 | def __init__(self): 37 | super(self.__class__, self).__init__() 38 | self.project_file = 'build.ninja' 39 | self.cmake_binary = 'cmake' 40 | self.android_ndk_folder = '~/ndk' 41 | self.clang_format_binary = 'clang-format' 42 | 43 | def generateProject(self, 44 | ub_sanitizer=False, 45 | address_sanitizer=False, 46 | mem_sanitizer=False, 47 | ios=False, 48 | android=False, 49 | android_arm=False, 50 | gcc=False): 51 | cmake_call = [ 52 | self.cmake_binary, 53 | '..', 54 | '-GNinja', 55 | '-DINCLUDE_LGPL=1', 56 | '-DUSE_FFMPEG=1'] 57 | if self.build_type == 'Release': 58 | cmake_call.append('-DCREATE_RELEASE_BUILD=1') 59 | else: 60 | cmake_call.append('-DCREATE_RELEASE_BUILD=0') 61 | if android or android_arm: 62 | android_abi = 'x86_64' 63 | android_toolchain_name = 'x86_64-llvm' 64 | if android_arm: 65 | android_abi = 'arm64-v8a' 66 | android_toolchain_name = 'arm64-llvm' 67 | cmake_call.extend([ 68 | '-DANDROID=1', 69 | '-DCMAKE_TOOLCHAIN_FILE=' + self.android_ndk_folder + '/build/cmake/android.toolchain.cmake', 70 | '-DANDROID_NDK=' + self.android_ndk_folder, 71 | '-DANDROID_ABI=' + android_abi, 72 | '-DANDROID_NATIVE_API_LEVEL=21', 73 | '-DANDROID_TOOLCHAIN_NAME=' + android_toolchain_name, 74 | '-DANDROID_STL=c++_shared']) 75 | if ub_sanitizer: 76 | cmake_call.append('-DUSE_UB_SANITIZER=1') 77 | if mem_sanitizer: 78 | cmake_call.append('-DUSE_MEM_SANITIZER=1') 79 | if address_sanitizer: 80 | cmake_call.append('-DUSE_ADDRESS_SANITIZER=1') 81 | if gcc: 82 | cmake_call.extend(['-DLLVM_STDLIB=0']) 83 | else: 84 | cmake_call.extend(['-DLLVM_STDLIB=1']) 85 | cmake_result = subprocess.call(cmake_call, cwd=self.build_directory) 86 | if cmake_result != 0: 87 | sys.exit(cmake_result) 88 | 89 | def buildTarget(self, target, sdk='', arch='x86_64'): 90 | ninja_result = subprocess.call([ 91 | 'ninja', 92 | '-C', 93 | self.build_directory, 94 | '-f', 95 | self.project_file, 96 | target]) 97 | if ninja_result != 0: 98 | sys.exit(ninja_result) 99 | 100 | def addLibraryPath(self, library_path): 101 | library_path_environment_variable = "LD_LIBRARY_PATH" 102 | if library_path_environment_variable in os.environ: 103 | os.environ[library_path_environment_variable] += os.pathsep + library_path 104 | else: 105 | os.environ[library_path_environment_variable] = library_path 106 | -------------------------------------------------------------------------------- /source/FactoryTransmuxerImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "FactoryTransmuxerImplementation.h" 22 | 23 | #include 24 | 25 | #include "DecoderDashToHLSTransmuxerImplementation.h" 26 | #include "Path.h" 27 | 28 | namespace nativeformat { 29 | namespace decoder { 30 | 31 | namespace { 32 | static const char DASH_FILE_INDICATOR[] = "ftypdash\0"; 33 | static const long DASH_FILE_INDICATOR_OFFSET = 4; 34 | } // namespace 35 | 36 | FactoryTransmuxerImplementation::FactoryTransmuxerImplementation( 37 | std::shared_ptr wrapped_factory, 38 | std::shared_ptr &data_provider_factory, 39 | std::shared_ptr &manifest_factory, 40 | std::shared_ptr &decrypter_factory) 41 | : _wrapped_factory(wrapped_factory), 42 | _data_provider_factory(data_provider_factory), 43 | _manifest_factory(manifest_factory), 44 | _decrypter_factory(decrypter_factory), 45 | _extensions_to_types({{NF_DECODER_MIME_TYPE_DASH_MP4, std::regex(".*\\.mp4")}}) {} 46 | 47 | FactoryTransmuxerImplementation::~FactoryTransmuxerImplementation() {} 48 | 49 | void FactoryTransmuxerImplementation::createDecoder( 50 | const std::string &path, 51 | const std::string &mime_type, 52 | const CREATE_DECODER_CALLBACK create_decoder_callback, 53 | const ERROR_DECODER_CALLBACK error_decoder_callback, 54 | double samplerate, 55 | int channels) { 56 | std::string mime_type_check = mime_type; 57 | if (mime_type_check.empty()) { 58 | for (auto it = _extensions_to_types.begin(); it != _extensions_to_types.end(); ++it) { 59 | auto &ext = it->second; 60 | if (std::regex_match(path, ext)) { 61 | mime_type_check = it->first; 62 | break; 63 | } 64 | } 65 | } 66 | bool should_process = 67 | #if USE_FFMPEG 68 | false; 69 | #else 70 | (NF_DECODER_DASH_MP4_MIME_TYPES.find(mime_type_check) != 71 | NF_DECODER_DASH_MP4_MIME_TYPES.end()); 72 | #endif 73 | 74 | if (should_process) { 75 | auto strong_this = shared_from_this(); 76 | _data_provider_factory->createDataProvider( 77 | path, 78 | [strong_this, path, error_decoder_callback, create_decoder_callback, mime_type]( 79 | const std::shared_ptr &data_provider) { 80 | if (!data_provider) { 81 | return; 82 | } 83 | data_provider->seek(DASH_FILE_INDICATOR_OFFSET, SEEK_SET); 84 | char FILE_INDICATOR[sizeof(DASH_FILE_INDICATOR)]; 85 | data_provider->read(&FILE_INDICATOR, sizeof(char), sizeof(FILE_INDICATOR)); 86 | std::string str = DASH_FILE_INDICATOR; 87 | bool is_dash_file = str.compare(FILE_INDICATOR) == 0; 88 | data_provider->seek(0, SEEK_SET); 89 | 90 | if (!is_dash_file) { 91 | strong_this->_wrapped_factory->createDecoder( 92 | path, 93 | mime_type, 94 | [create_decoder_callback, error_decoder_callback]( 95 | std::shared_ptr decoder) { create_decoder_callback(decoder); }, 96 | error_decoder_callback); 97 | return; 98 | } 99 | }, 100 | error_decoder_callback); 101 | return; 102 | } 103 | _wrapped_factory->createDecoder( 104 | path, 105 | mime_type, 106 | [create_decoder_callback, error_decoder_callback](std::shared_ptr decoder) { 107 | create_decoder_callback(decoder); 108 | }, 109 | error_decoder_callback); 110 | } 111 | 112 | } // namespace decoder 113 | } // namespace nativeformat 114 | -------------------------------------------------------------------------------- /source/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCE_FILES 2 | ../include/NFDecoder/NFDecoderMimeTypes.h 3 | ../include/NFDecoder/Factory.h 4 | ../include/NFDecoder/Decoder.h 5 | ../include/NFDecoder/DataProvider.h 6 | ../include/NFDecoder/DataProviderFactory.h 7 | ../include/NFDecoder/Decrypter.h 8 | ../include/NFDecoder/DecrypterFactory.h 9 | ../include/NFDecoder/Manifest.h 10 | ../include/NFDecoder/ManifestFactory.h 11 | NFDecoderMimeTypes.cpp 12 | Factory.cpp 13 | Decoder.cpp 14 | FactoryCommonImplementation.h 15 | FactoryCommonImplementation.cpp 16 | FactoryNormalisationImplementation.h 17 | FactoryNormalisationImplementation.cpp 18 | FactoryAppleImplementation.h 19 | FactoryAppleImplementation.cpp 20 | FactoryLGPLImplementation.h 21 | FactoryLGPLImplementation.cpp 22 | DataProvider.cpp 23 | DataProviderFactory.cpp 24 | DataProviderFactoryImplementation.h 25 | DataProviderFactoryImplementation.cpp 26 | DataProviderFileImplementation.h 27 | DataProviderFileImplementation.cpp 28 | DecoderOggImplementation.h 29 | DecoderOggImplementation.cpp 30 | DecoderVorbisImplementation.h 31 | DecoderVorbisImplementation.cpp 32 | DecoderOpusImplementation.h 33 | DecoderOpusImplementation.cpp 34 | DataProviderHTTPImplementation.h 35 | DataProviderHTTPImplementation.cpp 36 | DecoderWavImplementation.h 37 | DecoderWavImplementation.cpp 38 | DecoderAudioConverterImplementation.h 39 | DecoderAudioConverterImplementation.cpp 40 | DecoderAVCodecImplementation.h 41 | DecoderAVCodecImplementation.cpp 42 | DecoderNormalisationImplementation.h 43 | DecoderNormalisationImplementation.cpp 44 | DecoderMidiImplementation.h 45 | DecoderMidiImplementation.cpp 46 | base64.h 47 | base64.cpp 48 | DecrypterFactory.cpp 49 | DecrypterFactoryImplementation.h 50 | DecrypterFactoryImplementation.cpp 51 | Path.h 52 | Path.cpp 53 | LicenseManager.h 54 | ManifestFactory.cpp 55 | ManifestFactoryImplementation.h 56 | ManifestFactoryImplementation.cpp 57 | Decrypter.cpp 58 | LicenseManager.cpp 59 | FactoryServiceImplementation.h 60 | FactoryServiceImplementation.cpp 61 | DataProviderMemoryImplementation.h 62 | DataProviderMemoryImplementation.cpp 63 | DecoderFLACImplementation.h 64 | DecoderFLACImplementation.cpp 65 | DecoderDashToHLSTransmuxerImplementation.h 66 | DecoderDashToHLSTransmuxerImplementation.cpp 67 | FactoryTransmuxerImplementation.h 68 | FactoryTransmuxerImplementation.cpp 69 | DecoderAndroidImplementation.h 70 | DecoderAndroidImplementation.cpp 71 | FactoryAndroidImplementation.h 72 | FactoryAndroidImplementation.cpp 73 | DecoderSpeexImplementation.h 74 | DecoderSpeexImplementation.cpp) 75 | set(LINK_LIBRARIES 76 | ogg 77 | vorbis 78 | vorbisfile 79 | opus 80 | opusfile 81 | libresample 82 | NFHTTP 83 | ${OPENSSL_LIBRARIES} 84 | flac 85 | TinySoundFont 86 | speex 87 | ) 88 | set(INCLUDE_DIRS 89 | ../include 90 | ../libraries/vorbis/include 91 | ../libraries/opus/include 92 | ${OPUSFILE_INCLUDE_DIR} 93 | ../libraries/ogg/include 94 | ../libraries/NFHTTP/include 95 | ../libraries/universal-dash-transmuxer/include 96 | ../libraries/speex/include 97 | ${CMAKE_BINARY_DIR}/output) 98 | 99 | if(INCLUDE_UDT) 100 | set(DASH_LIBRARIES 101 | DashToHlsLibrary 102 | DashToHlsDash 103 | DashToHlsTs 104 | DashToHlsPs 105 | ) 106 | list(APPEND LINK_LIBRARIES ${DASH_LIBRARIES}) 107 | endif() 108 | 109 | if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 110 | find_library(AUDIO_TOOLBOX AudioToolbox) 111 | list(APPEND LINK_LIBRARIES ${AUDIO_TOOLBOX}) 112 | endif() 113 | 114 | if(FFMPEG_FOUND) 115 | list(APPEND LINK_LIBRARIES 116 | AvCodec 117 | AvDevice 118 | AvFilter 119 | AvFormat 120 | AvResample 121 | AvUtil 122 | SwResample 123 | SwScale) 124 | list(APPEND INCLUDE_DIRS ${FFMPEG_INCLUDE_DIR}) 125 | endif() 126 | 127 | add_library(NFDecoder STATIC ${SOURCE_FILES}) 128 | target_include_directories(NFDecoder PUBLIC ../include PRIVATE ${INCLUDE_DIRS}) 129 | if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 130 | target_link_libraries(NFDecoder ${LINK_LIBRARIES}) 131 | else() 132 | target_link_libraries(NFDecoder -Wl,--start-group 133 | ${LINK_LIBRARIES} 134 | -Wl,--end-group) 135 | endif() 136 | 137 | if(NOT IOS) 138 | add_subdirectory(cli) 139 | endif() 140 | 141 | if(USE_FFMPEG) 142 | target_compile_definitions(NFDecoder PRIVATE USE_FFMPEG=1) 143 | endif() 144 | 145 | if(INCLUDE_UDT) 146 | add_definitions(-DINCLUDE_UDT=1) 147 | endif() 148 | -------------------------------------------------------------------------------- /source/DecoderFLACImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | namespace nativeformat { 36 | namespace decoder { 37 | 38 | typedef std::function LOAD_DECODER_CALLBACK; 39 | 40 | class DecoderFLACImplementation : public Decoder, 41 | public std::enable_shared_from_this { 42 | public: 43 | typedef enum : int { ErrorCodeNotEnoughData, ErrorCodeCouldNotDecode } ErrorCode; 44 | 45 | DecoderFLACImplementation(std::shared_ptr &data_provider); 46 | virtual ~DecoderFLACImplementation(); 47 | 48 | // Decoder 49 | virtual double sampleRate(); 50 | virtual int channels(); 51 | virtual long currentFrameIndex(); 52 | virtual void seek(long frame_index); 53 | virtual long frames(); 54 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous); 55 | virtual bool eof(); 56 | virtual const std::string &path(); 57 | virtual const std::string &name(); 58 | virtual void flush(); 59 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 60 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 61 | 62 | private: 63 | static FLAC__StreamDecoderReadStatus flac_read(const FLAC__StreamDecoder *decoder, 64 | FLAC__byte buffer[], 65 | size_t *bytes, 66 | void *client_data); 67 | static FLAC__StreamDecoderSeekStatus flac_seek(const FLAC__StreamDecoder *decoder, 68 | FLAC__uint64 absolute_byte_offset, 69 | void *client_data); 70 | static FLAC__StreamDecoderTellStatus flac_tell(const FLAC__StreamDecoder *decoder, 71 | FLAC__uint64 *absolute_byte_offset, 72 | void *client_data); 73 | static FLAC__StreamDecoderLengthStatus flac_length(const FLAC__StreamDecoder *decoder, 74 | FLAC__uint64 *stream_length, 75 | void *client_data); 76 | static FLAC__bool flac_eof(const FLAC__StreamDecoder *decoder, void *client_data); 77 | static FLAC__StreamDecoderWriteStatus flac_write(const FLAC__StreamDecoder *decoder, 78 | const FLAC__Frame *frame, 79 | const FLAC__int32 *const buffer[], 80 | void *client_data); 81 | static void flac_metadata(const FLAC__StreamDecoder *decoder, 82 | const FLAC__StreamMetadata *metadata, 83 | void *client_data); 84 | static void flac_error(const FLAC__StreamDecoder *decoder, 85 | FLAC__StreamDecoderErrorStatus status, 86 | void *client_data); 87 | 88 | std::shared_ptr _data_provider; 89 | 90 | FLAC__StreamDecoder *_flac_decoder; 91 | std::mutex _flac_decoder_mutex; 92 | std::future _load_future; 93 | std::atomic _channels; 94 | std::atomic _samplerate; 95 | std::atomic _frame_index; 96 | std::atomic _frames; 97 | std::vector _samples; 98 | std::mutex _samples_mutex; 99 | }; 100 | 101 | } // namespace decoder 102 | } // namespace nativeformat 103 | -------------------------------------------------------------------------------- /ci/nfbuildwindows.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | * Copyright (c) 2018 Spotify AB. 4 | * 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, 16 | * software distributed under the License is distributed on an 17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 | * KIND, either express or implied. See the License for the 19 | * specific language governing permissions and limitations 20 | * under the License. 21 | ''' 22 | 23 | 24 | import fnmatch 25 | import os 26 | import plistlib 27 | import re 28 | import shutil 29 | import subprocess 30 | import sys 31 | 32 | from distutils import dir_util 33 | from nfbuild import NFBuild 34 | 35 | 36 | class NFBuildWindows(NFBuild): 37 | def __init__(self): 38 | super(self.__class__, self).__init__() 39 | self.project_file = 'build.ninja' 40 | 41 | def installClangFormat(self): 42 | clang_format_vulcan_file = os.path.join('tools', 'clang-format.vulcan') 43 | clang_format_extraction_folder = self.vulcanDownload( 44 | clang_format_vulcan_file, 45 | 'clang-format-5.0.0') 46 | self.clang_format_binary = os.path.join( 47 | os.path.join( 48 | os.path.join( 49 | clang_format_extraction_folder, 50 | 'clang-format'), 51 | 'bin'), 52 | 'clang-format') 53 | 54 | def installNinja(self): 55 | ninja_vulcan_file = os.path.join( 56 | os.path.join( 57 | os.path.join( 58 | os.path.join('tools', 'buildtools'), 59 | 'spotify_buildtools'), 60 | 'software'), 61 | 'ninja.vulcan') 62 | ninja_extraction_folder = self.vulcanDownload( 63 | ninja_vulcan_file, 64 | 'ninja-1.6.0') 65 | self.ninja_binary = os.path.join( 66 | ninja_extraction_folder, 67 | 'ninja') 68 | if 'PATH' not in os.environ: 69 | os.environ['PATH'] = '' 70 | if len(os.environ['PATH']) > 0: 71 | os.environ['PATH'] += os.pathsep 72 | os.environ['PATH'] += ninja_extraction_folder 73 | 74 | def installMake(self): 75 | make_vulcan_file = os.path.join('tools', 'make.vulcan') 76 | make_extraction_folder = self.vulcanDownload( 77 | make_vulcan_file, 78 | 'make-4.2.1') 79 | make_bin_folder = os.path.join( 80 | make_extraction_folder, 81 | 'bin') 82 | os.environ['PATH'] += os.pathsep + make_bin_folder 83 | 84 | def installVulcanDependencies(self, android=False): 85 | super(self.__class__, self).installVulcanDependencies(android) 86 | self.installClangFormat() 87 | self.installMake() 88 | if android: 89 | self.installNinja() 90 | 91 | def generateProject(self, 92 | ios=False, 93 | android=False, 94 | android_arm=False): 95 | self.use_ninja = android or android_arm 96 | cmake_call = [ 97 | self.cmake_binary, 98 | '..', 99 | '-GNinja'] 100 | if android or android_arm: 101 | android_abi = 'x86_64' 102 | android_toolchain_name = 'x86_64-llvm' 103 | if android_arm: 104 | android_abi = 'arm64-v8a' 105 | android_toolchain_name = 'arm64-llvm' 106 | cmake_call.extend([ 107 | '-DANDROID=1', 108 | '-DCMAKE_TOOLCHAIN_FILE=' + self.android_ndk_folder + '/build/cmake/android.toolchain.cmake', 109 | '-DANDROID_NDK=' + self.android_ndk_folder, 110 | '-DANDROID_ABI=' + android_abi, 111 | '-DANDROID_NATIVE_API_LEVEL=21', 112 | '-DANDROID_TOOLCHAIN_NAME=' + android_toolchain_name, 113 | '-DANDROID_WINDOWS=1', 114 | '-DANDROID_STL=c++_shared']) 115 | cmake_result = subprocess.call(cmake_call, cwd=self.build_directory) 116 | if cmake_result != 0: 117 | sys.exit(cmake_result) 118 | 119 | def buildTarget(self, target, sdk='macosx', arch='x86_64'): 120 | result = subprocess.call([ 121 | self.ninja_binary, 122 | '-C', 123 | self.build_directory, 124 | '-f', 125 | self.project_file, 126 | target]) 127 | if result != 0: 128 | sys.exit(result) 129 | -------------------------------------------------------------------------------- /source/DecoderWavImplementation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | namespace nativeformat { 33 | namespace decoder { 34 | 35 | typedef std::function LOAD_DECODER_CALLBACK; 36 | 37 | class DecoderWavImplementation : public Decoder, 38 | public std::enable_shared_from_this { 39 | public: 40 | typedef enum : int { 41 | ErrorCodeNotEnoughDataForHeader, 42 | ErrorCodeCouldNotDecodeHeader, 43 | ErrorCodeNotRiff, 44 | ErrorCodeNotWav, 45 | ErrorCodeChunkError 46 | } ErrorCode; 47 | 48 | DecoderWavImplementation(std::shared_ptr &data_provider); 49 | virtual ~DecoderWavImplementation(); 50 | 51 | // Decoder 52 | virtual double sampleRate(); 53 | virtual int channels(); 54 | virtual long currentFrameIndex(); 55 | virtual void seek(long frame_index); 56 | virtual long frames(); 57 | virtual void decode(long frames, const DECODE_CALLBACK &decode_callback, bool synchronous); 58 | virtual bool eof(); 59 | virtual const std::string &path(); 60 | virtual const std::string &name(); 61 | virtual void flush(); 62 | virtual void load(const ERROR_DECODER_CALLBACK &decoder_error_callback, 63 | const LOAD_DECODER_CALLBACK &decoder_load_callback); 64 | 65 | private: 66 | typedef enum : short { 67 | WAVHeaderAudioFormatNone = 0, 68 | WAVHeaderAudioFormatPCM = 1, 69 | WAVHeaderAudioFormatIEEEFloat = 3 70 | } WAVHeaderAudioFormat; 71 | 72 | #pragma pack(push, 1) 73 | typedef struct WAVHeader { 74 | // RIFF 75 | char riff_header_name[4]; 76 | uint32_t file_size; 77 | char wave_header_name[4]; 78 | } WAVHeader; 79 | 80 | typedef struct FMTHeader { 81 | uint32_t chunk_size; 82 | WAVHeaderAudioFormat audio_format; 83 | uint16_t channels; 84 | uint32_t sample_rate; 85 | uint32_t byte_rate; 86 | uint16_t sample_alignment; 87 | uint16_t bit_depth; 88 | } FMTHeader; 89 | 90 | typedef struct DATAHeader { 91 | uint32_t data_bytes; 92 | } DATAHeader; 93 | #pragma pack(pop) 94 | 95 | bool readChunk(); 96 | bool knownType(); 97 | static size_t wavSampleSize(const FMTHeader &header); 98 | 99 | std::shared_ptr _data_provider; 100 | const ERROR_DECODER_CALLBACK _decoder_error_callback; 101 | 102 | std::mutex _wav_mutex; 103 | std::atomic _channels; 104 | std::atomic _samplerate; 105 | std::atomic _frames; 106 | std::atomic _frame_size; 107 | std::atomic _frame_index; 108 | std::future _load_future; 109 | char _chunk_type[4]; 110 | WAVHeader _header; 111 | FMTHeader _fmt; 112 | size_t _data_offset; 113 | uint32_t _data_bytes; 114 | }; 115 | 116 | template 117 | struct WavReader { 118 | std::vector in_samples; 119 | std::vector out_samples; 120 | DataProvider *dp; 121 | static constexpr size_t sample_size = sizeof(sample_t); 122 | 123 | WavReader(DataProvider *data_provider, size_t frames, size_t channels) 124 | : in_samples(frames * channels), dp(data_provider) {} 125 | ~WavReader() {} 126 | 127 | size_t transferSamples(size_t frames, size_t channels) { 128 | size_t bytes_read = dp->read((char *)in_samples.data(), sample_size * channels, frames); 129 | size_t frames_read = bytes_read / (sample_size * channels); 130 | out_samples.resize(frames_read * channels); 131 | static constexpr float s_min = static_cast(std::numeric_limits::min()); 132 | static constexpr float s_max = static_cast(std::numeric_limits::max()); 133 | static constexpr sample_t dc_offset = s_min ? 0 : s_max / 2; 134 | for (long i = 0; i < frames_read * channels; ++i) { 135 | float sample = static_cast(in_samples[i] - dc_offset) / 136 | static_cast(std::numeric_limits::max()); 137 | out_samples[i] = sample; 138 | } 139 | return frames_read; 140 | } 141 | }; 142 | 143 | } // namespace decoder 144 | } // namespace nativeformat 145 | -------------------------------------------------------------------------------- /source/Factory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include 22 | 23 | #include "FactoryAndroidImplementation.h" 24 | #include "FactoryAppleImplementation.h" 25 | #include "FactoryCommonImplementation.h" 26 | #include "FactoryLGPLImplementation.h" 27 | #include "FactoryNormalisationImplementation.h" 28 | #include "FactoryServiceImplementation.h" 29 | #include "FactoryTransmuxerImplementation.h" 30 | 31 | namespace nativeformat { 32 | namespace decoder { 33 | 34 | const double STANDARD_SAMPLERATE = 44100.0; 35 | const int STANDARD_CHANNELS = 2; 36 | 37 | std::shared_ptr createCommonFactory( 38 | std::shared_ptr data_provider_factory, 39 | std::shared_ptr decrypter_factory, 40 | std::shared_ptr manifest_factory) { 41 | return std::make_shared(data_provider_factory); 42 | } 43 | 44 | std::shared_ptr createPlatformFactory( 45 | std::shared_ptr data_provider_factory, 46 | std::shared_ptr decrypter_factory, 47 | std::shared_ptr manifest_factory) { 48 | std::shared_ptr common_factory = 49 | createCommonFactory(data_provider_factory, decrypter_factory, manifest_factory); 50 | #if __APPLE__ && !USE_FFMPEG 51 | return std::make_shared(common_factory, data_provider_factory); 52 | #endif 53 | #if ANDROID 54 | return std::make_shared(common_factory, data_provider_factory); 55 | #endif 56 | return common_factory; 57 | } 58 | 59 | std::shared_ptr createLGPLFactory( 60 | std::shared_ptr data_provider_factory, 61 | std::shared_ptr decrypter_factory, 62 | std::shared_ptr manifest_factory) { 63 | std::shared_ptr platform_factory = 64 | createPlatformFactory(data_provider_factory, decrypter_factory, manifest_factory); 65 | #if INCLUDE_LGPL 66 | return std::make_shared( 67 | platform_factory, data_provider_factory, decrypter_factory); 68 | #endif 69 | return platform_factory; 70 | } 71 | 72 | std::shared_ptr createTransmuxerFactory( 73 | std::shared_ptr data_provider_factory, 74 | std::shared_ptr decrypter_factory, 75 | std::shared_ptr manifest_factory) { 76 | auto lgpl_factory = createLGPLFactory(data_provider_factory, decrypter_factory, manifest_factory); 77 | return std::make_shared( 78 | lgpl_factory, data_provider_factory, manifest_factory, decrypter_factory); 79 | } 80 | 81 | std::shared_ptr createNormalisationFactory( 82 | std::shared_ptr data_provider_factory, 83 | std::shared_ptr decrypter_factory, 84 | std::shared_ptr manifest_factory) { 85 | return std::make_shared( 86 | createTransmuxerFactory(data_provider_factory, decrypter_factory, manifest_factory)); 87 | } 88 | 89 | std::shared_ptr createServiceFactory( 90 | std::shared_ptr data_provider_factory, 91 | std::shared_ptr decrypter_factory, 92 | std::shared_ptr manifest_factory) { 93 | return std::make_shared( 94 | createNormalisationFactory(data_provider_factory, decrypter_factory, manifest_factory), 95 | data_provider_factory, 96 | manifest_factory, 97 | decrypter_factory); 98 | } 99 | 100 | std::shared_ptr createFactory(std::shared_ptr data_provider_factory, 101 | std::shared_ptr decrypter_factory, 102 | std::shared_ptr manifest_factory) { 103 | if (!data_provider_factory) { 104 | data_provider_factory = createDataProviderFactory(); 105 | } 106 | if (!decrypter_factory) { 107 | decrypter_factory = createDecrypterFactory(); 108 | } 109 | if (!manifest_factory) { 110 | manifest_factory = createManifestFactory(); 111 | } 112 | return createServiceFactory(data_provider_factory, decrypter_factory, manifest_factory); 113 | } 114 | 115 | } // namespace decoder 116 | } // namespace nativeformat 117 | -------------------------------------------------------------------------------- /source/DataProviderHTTPImplementation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Spotify AB. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | #include "DataProviderHTTPImplementation.h" 22 | 23 | #include 24 | 25 | namespace nativeformat { 26 | namespace decoder { 27 | 28 | DataProviderHTTPImplementation::DataProviderHTTPImplementation(const std::string &path, 29 | std::shared_ptr client) 30 | : _path(path), 31 | _client(client ?: http::createClient(http::standardCacheLocation(), "")), 32 | _content_length(0), 33 | _offset(0) {} 34 | 35 | DataProviderHTTPImplementation::~DataProviderHTTPImplementation() {} 36 | 37 | const std::string &DataProviderHTTPImplementation::name() { 38 | static const std::string domain("com.nativeformat.decoder.http"); 39 | return domain; 40 | } 41 | 42 | void DataProviderHTTPImplementation::load( 43 | const ERROR_DATA_PROVIDER_CALLBACK &data_provider_error_callback, 44 | const LOAD_DATA_PROVIDER_CALLBACK &data_provider_load_callback) { 45 | // Perform a HEAD request to check whether the entity is there and get the 46 | // content length 47 | std::shared_ptr request = http::createRequest(_path, {}); 48 | request->setMethod(http::HeadMethod); 49 | std::shared_ptr strong_this = shared_from_this(); 50 | _client->performRequest( 51 | request, 52 | [strong_this, data_provider_load_callback, data_provider_error_callback]( 53 | const std::shared_ptr &response) { 54 | static const std::string content_length_header = "Content-Length"; 55 | if (response->statusCode() != http::StatusCodeOK) { 56 | data_provider_error_callback(strong_this->name(), response->statusCode()); 57 | data_provider_load_callback(false); 58 | return; 59 | } 60 | std::string content_length = (*response)[content_length_header]; 61 | std::stringstream content_length_stream(content_length); 62 | size_t content_length_primitive = 0; 63 | content_length_stream >> content_length_primitive; 64 | strong_this->_content_length = content_length_primitive; 65 | strong_this->_load_future = std::async(std::launch::async, [data_provider_load_callback]() { 66 | data_provider_load_callback(true); 67 | }); 68 | }); 69 | } 70 | 71 | size_t DataProviderHTTPImplementation::read(void *ptr, size_t size, size_t nmemb) { 72 | std::lock_guard read_lock(_read_mutex); 73 | if (_offset >= _content_length) { 74 | return 0; 75 | } 76 | size_t offset = _offset; 77 | size_t new_offset = (offset + (size * nmemb)) - 1; 78 | std::shared_ptr request = http::createRequest( 79 | _path, {{"Range", "bytes=" + std::to_string(offset) + "-" + std::to_string(new_offset)}}); 80 | std::shared_ptr response = _client->performRequestSynchronously(request); 81 | size_t data_length = 0; 82 | const unsigned char *data = response->data(data_length); 83 | if (data == nullptr) { 84 | return 0; 85 | } 86 | memcpy(ptr, data, data_length); 87 | _offset = offset + data_length; 88 | return data_length; 89 | } 90 | 91 | int DataProviderHTTPImplementation::seek(long offset, int whence) { 92 | std::lock_guard read_lock(_read_mutex); 93 | size_t new_offset = 0; 94 | size_t content_length = _content_length; 95 | switch (whence) { 96 | case SEEK_SET: 97 | new_offset = offset; 98 | break; 99 | case SEEK_CUR: 100 | new_offset = _offset + offset; 101 | break; 102 | case SEEK_END: 103 | new_offset = content_length + offset; 104 | break; 105 | } 106 | if (new_offset > content_length) { 107 | return EOF; 108 | } 109 | _offset = new_offset; 110 | return 0; 111 | } 112 | 113 | long DataProviderHTTPImplementation::tell() { 114 | std::lock_guard read_lock(_read_mutex); 115 | return _offset; 116 | } 117 | 118 | const std::string &DataProviderHTTPImplementation::path() { 119 | return _path; 120 | } 121 | 122 | bool DataProviderHTTPImplementation::eof() { 123 | std::lock_guard read_lock(_read_mutex); 124 | return _offset >= _content_length; 125 | } 126 | 127 | long DataProviderHTTPImplementation::size() { 128 | return _content_length; 129 | } 130 | 131 | } // namespace decoder 132 | } // namespace nativeformat 133 | --------------------------------------------------------------------------------