diff --git a/README.dev.md b/README.dev.md index 7c522b37..2cda0e8b 100644 --- a/README.dev.md +++ b/README.dev.md @@ -848,18 +848,18 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - + - name: Set up JDK uses: actions/setup-java@v2 with: distribution: 'adopt' java-version: '17' - + - name: Run dry-run tests run: | export ANDROID_SERIAL=${{ secrets.DEVICE_SERIAL }} ./scripts/release.sh --dry-run - + - name: Upload APK uses: actions/upload-artifact@v2 with: @@ -872,18 +872,18 @@ jobs: ```groovy pipeline { agent any - + environment { ANDROID_SERIAL = credentials('android-device-serial') } - + stages { stage('Test') { steps { sh './scripts/release.sh --dry-run' } } - + stage('Build Release') { when { branch 'main' @@ -893,7 +893,7 @@ pipeline { } } } - + post { success { archiveArtifacts 'app/releases/*.apk' @@ -936,3 +936,19 @@ export ANDROID_SERIAL=emulator-5554 - `0` - Success - `1` - Error (build failure, test failure, user abort, etc.) + +# 6. Native Modules + +## 6.1. libX264 + +### 6.1.1. iOS + +Building libX264 for iOS: + +```bash +export CC="xcrun --sdk iphoneos clang" +export CFLAGS="-arch arm64 -mios-version-min=11.0 -isysroot $(xcrun --sdk iphoneos --show-sdk-path)" +export LDFLAGS="-arch arm64 -mios-version-min=11.0 -isysroot $(xcrun --sdk iphoneos --show-sdk-path)" +./configure --host=aarch64-apple-darwin --enable-static --enable-pic --disable-cli +make -jX +``` diff --git a/ios/Encapp.xcodeproj/project.pbxproj b/ios/Encapp.xcodeproj/project.pbxproj index e1f6ea18..507c515b 100644 --- a/ios/Encapp.xcodeproj/project.pbxproj +++ b/ios/Encapp.xcodeproj/project.pbxproj @@ -8,8 +8,27 @@ /* Begin PBXBuildFile section */ CA53D6F729689DB200485E4D /* Decoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA53D6F629689DB200485E4D /* Decoder.swift */; }; - CA8256F6293E7BEB0082B2BE /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = CA8256F5293E7BEB0082B2BE /* SwiftProtobuf */; }; - CA8256F8293E7BEB0082B2BE /* SwiftProtobufPluginLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = CA8256F7293E7BEB0082B2BE /* SwiftProtobufPluginLibrary */; }; + CA84B4C02ED6264F00D19FBE /* FrameInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9309293911E8009009B2 /* FrameInfo.swift */; }; + CA84B4C12ED6264F00D19FBE /* ListProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92F7292D2BD5009009B2 /* ListProperties.swift */; }; + CA84B4C22ED6264F00D19FBE /* EncappMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAE00007293E907400727B6D /* EncappMain.swift */; }; + CA84B4C32ED6264F00D19FBE /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92C7292D2ABB009009B2 /* ContentView.swift */; }; + CA84B4C42ED6264F00D19FBE /* Encoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92FF292E7C40009009B2 /* Encoder.swift */; }; + CA84B4C52ED6264F00D19FBE /* LocalLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAE00009293EAA8200727B6D /* LocalLogger.swift */; }; + CA84B4C62ED6264F00D19FBE /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9302292E92EC009009B2 /* Utils.swift */; }; + CA84B4C72ED6264F00D19FBE /* FileHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92FC292D7A44009009B2 /* FileHandling.swift */; }; + CA84B4C82ED6264F00D19FBE /* EncappApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92C5292D2ABB009009B2 /* EncappApp.swift */; }; + CA84B4C92ED6264F00D19FBE /* TestRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB930F29395655009009B2 /* TestRunner.swift */; }; + CA84B4CA2ED6264F00D19FBE /* Statistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9306293910D9009009B2 /* Statistics.swift */; }; + CA84B4CB2ED6264F00D19FBE /* tests.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92F5292D2B88009009B2 /* tests.pb.swift */; }; + CA84B4CC2ED6264F00D19FBE /* X264Encoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA707E7E2E97133C00ABC79F /* X264Encoder.swift */; }; + CA84B4CD2ED6264F00D19FBE /* CodecHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9312293A7478009009B2 /* CodecHelper.swift */; }; + CA84B4CE2ED6264F00D19FBE /* Decoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA53D6F629689DB200485E4D /* Decoder.swift */; }; + CA84B4CF2ED6264F00D19FBE /* JsonStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB930C29392CC8009009B2 /* JsonStats.swift */; }; + CA84B4D12ED6264F00D19FBE /* libx264.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CA707E842E97238C00ABC79F /* libx264.a */; }; + CA84B4D22ED6264F00D19FBE /* SwiftProtobufPluginLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = CA84B4BE2ED6264F00D19FBE /* SwiftProtobufPluginLibrary */; }; + CA84B4D32ED6264F00D19FBE /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = CA84B4BC2ED6264F00D19FBE /* SwiftProtobuf */; }; + CA84B4D52ED6264F00D19FBE /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CAAB92CD292D2ABC009009B2 /* Preview Assets.xcassets */; }; + CA84B4D62ED6264F00D19FBE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CAAB92C9292D2ABC009009B2 /* Assets.xcassets */; }; CAAB92C6292D2ABB009009B2 /* EncappApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92C5292D2ABB009009B2 /* EncappApp.swift */; }; CAAB92C8292D2ABB009009B2 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92C7292D2ABB009009B2 /* ContentView.swift */; }; CAAB92CA292D2ABC009009B2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CAAB92C9292D2ABC009009B2 /* Assets.xcassets */; }; @@ -18,35 +37,19 @@ CAAB92F4292D2ADF009009B2 /* SwiftProtobufPluginLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = CAAB92F3292D2ADF009009B2 /* SwiftProtobufPluginLibrary */; }; CAAB92F6292D2B89009009B2 /* tests.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92F5292D2B88009009B2 /* tests.pb.swift */; }; CAAB92F8292D2BD5009009B2 /* ListProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92F7292D2BD5009009B2 /* ListProperties.swift */; }; - CAAB92FB292D380F009009B2 /* ListProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92F7292D2BD5009009B2 /* ListProperties.swift */; }; CAAB92FD292D7A44009009B2 /* FileHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92FC292D7A44009009B2 /* FileHandling.swift */; }; - CAAB92FE292D7A44009009B2 /* FileHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92FC292D7A44009009B2 /* FileHandling.swift */; }; CAAB9300292E7C40009009B2 /* Encoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92FF292E7C40009009B2 /* Encoder.swift */; }; - CAAB9301292E7C40009009B2 /* Encoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB92FF292E7C40009009B2 /* Encoder.swift */; }; CAAB9303292E92EC009009B2 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9302292E92EC009009B2 /* Utils.swift */; }; - CAAB9304292E92EC009009B2 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9302292E92EC009009B2 /* Utils.swift */; }; CAAB9307293910D9009009B2 /* Statistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9306293910D9009009B2 /* Statistics.swift */; }; - CAAB9308293910D9009009B2 /* Statistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9306293910D9009009B2 /* Statistics.swift */; }; CAAB930A293911E8009009B2 /* FrameInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9309293911E8009009B2 /* FrameInfo.swift */; }; - CAAB930B293911E8009009B2 /* FrameInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9309293911E8009009B2 /* FrameInfo.swift */; }; CAAB930D29392CC8009009B2 /* JsonStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB930C29392CC8009009B2 /* JsonStats.swift */; }; - CAAB930E29392CC8009009B2 /* JsonStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB930C29392CC8009009B2 /* JsonStats.swift */; }; CAAB931029395655009009B2 /* TestRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB930F29395655009009B2 /* TestRunner.swift */; }; - CAAB931129395655009009B2 /* TestRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB930F29395655009009B2 /* TestRunner.swift */; }; CAAB9313293A7478009009B2 /* CodecHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9312293A7478009009B2 /* CodecHelper.swift */; }; - CAAB9314293A7478009009B2 /* CodecHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAB9312293A7478009009B2 /* CodecHelper.swift */; }; CAE00008293E907400727B6D /* EncappMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAE00007293E907400727B6D /* EncappMain.swift */; }; CAE0000A293EAA8200727B6D /* LocalLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAE00009293EAA8200727B6D /* LocalLogger.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - CAAB92D4292D2ABD009009B2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CAAB92BA292D2ABB009009B2 /* Project object */; - proxyType = 1; - remoteGlobalIDString = CAAB92C1292D2ABB009009B2; - remoteInfo = Encapp; - }; CAAB92DE292D2ABD009009B2 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = CAAB92BA292D2ABB009009B2 /* Project object */; @@ -58,13 +61,16 @@ /* Begin PBXFileReference section */ CA53D6F629689DB200485E4D /* Decoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Decoder.swift; sourceTree = ""; }; + CA707E7E2E97133C00ABC79F /* X264Encoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = X264Encoder.swift; sourceTree = ""; }; + CA707E842E97238C00ABC79F /* libx264.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libx264.a; sourceTree = ""; }; + CA707E8B2E9882E300ABC79F /* X264WrapperBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = X264WrapperBridge.h; sourceTree = ""; }; + CA84B4DA2ED6264F00D19FBE /* Encapp.x264.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Encapp.x264.app; sourceTree = BUILT_PRODUCTS_DIR; }; CAAB92C2292D2ABB009009B2 /* Encapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Encapp.app; sourceTree = BUILT_PRODUCTS_DIR; }; CAAB92C5292D2ABB009009B2 /* EncappApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncappApp.swift; sourceTree = ""; }; CAAB92C7292D2ABB009009B2 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; CAAB92C9292D2ABC009009B2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; CAAB92CB292D2ABC009009B2 /* Encapp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Encapp.entitlements; sourceTree = ""; }; CAAB92CD292D2ABC009009B2 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - CAAB92D3292D2ABD009009B2 /* EncappTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = EncappTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CAAB92DD292D2ABD009009B2 /* EncappUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = EncappUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CAAB92F5292D2B88009009B2 /* tests.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = tests.pb.swift; sourceTree = ""; }; CAAB92F7292D2BD5009009B2 /* ListProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListProperties.swift; sourceTree = ""; }; @@ -81,21 +87,22 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - CAAB92BF292D2ABB009009B2 /* Frameworks */ = { + CA84B4D02ED6264F00D19FBE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CAAB92F4292D2ADF009009B2 /* SwiftProtobufPluginLibrary in Frameworks */, - CAAB92F2292D2ADF009009B2 /* SwiftProtobuf in Frameworks */, + CA84B4D12ED6264F00D19FBE /* libx264.a in Frameworks */, + CA84B4D22ED6264F00D19FBE /* SwiftProtobufPluginLibrary in Frameworks */, + CA84B4D32ED6264F00D19FBE /* SwiftProtobuf in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - CAAB92D0292D2ABD009009B2 /* Frameworks */ = { + CAAB92BF292D2ABB009009B2 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CA8256F8293E7BEB0082B2BE /* SwiftProtobufPluginLibrary in Frameworks */, - CA8256F6293E7BEB0082B2BE /* SwiftProtobuf in Frameworks */, + CAAB92F4292D2ADF009009B2 /* SwiftProtobufPluginLibrary in Frameworks */, + CAAB92F2292D2ADF009009B2 /* SwiftProtobuf in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -109,6 +116,22 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + CA707E852E97238C00ABC79F /* libs */ = { + isa = PBXGroup; + children = ( + CA707E842E97238C00ABC79F /* libx264.a */, + ); + path = libs; + sourceTree = ""; + }; + CA707E892E97255A00ABC79F /* ObjC */ = { + isa = PBXGroup; + children = ( + CA707E8B2E9882E300ABC79F /* X264WrapperBridge.h */, + ); + path = ObjC; + sourceTree = ""; + }; CA8256F4293E7BDF0082B2BE /* Frameworks */ = { isa = PBXGroup; children = ( @@ -119,6 +142,8 @@ CAAB92B9292D2ABB009009B2 = { isa = PBXGroup; children = ( + CA707E892E97255A00ABC79F /* ObjC */, + CA707E852E97238C00ABC79F /* libs */, CAAB92C4292D2ABB009009B2 /* Encapp */, CAAB92C3292D2ABB009009B2 /* Products */, CA8256F4293E7BDF0082B2BE /* Frameworks */, @@ -129,8 +154,8 @@ isa = PBXGroup; children = ( CAAB92C2292D2ABB009009B2 /* Encapp.app */, - CAAB92D3292D2ABD009009B2 /* EncappTests.xctest */, CAAB92DD292D2ABD009009B2 /* EncappUITests.xctest */, + CA84B4DA2ED6264F00D19FBE /* Encapp.x264.app */, ); name = Products; sourceTree = ""; @@ -142,6 +167,7 @@ CAAB92F5292D2B88009009B2 /* tests.pb.swift */, CAAB930F29395655009009B2 /* TestRunner.swift */, CAAB92FF292E7C40009009B2 /* Encoder.swift */, + CA707E7E2E97133C00ABC79F /* X264Encoder.swift */, CA53D6F629689DB200485E4D /* Decoder.swift */, CAAB92C5292D2ABB009009B2 /* EncappApp.swift */, CAAB92C7292D2ABB009009B2 /* ContentView.swift */, @@ -179,48 +205,47 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - CAAB92C1292D2ABB009009B2 /* Encapp */ = { + CA84B4BB2ED6264F00D19FBE /* Encapp.x264 */ = { isa = PBXNativeTarget; - buildConfigurationList = CAAB92E7292D2ABD009009B2 /* Build configuration list for PBXNativeTarget "Encapp" */; + buildConfigurationList = CA84B4D72ED6264F00D19FBE /* Build configuration list for PBXNativeTarget "Encapp.x264" */; buildPhases = ( - CAAB92BE292D2ABB009009B2 /* Sources */, - CAAB92BF292D2ABB009009B2 /* Frameworks */, - CAAB92C0292D2ABB009009B2 /* Resources */, + CA84B4BF2ED6264F00D19FBE /* Sources */, + CA84B4D02ED6264F00D19FBE /* Frameworks */, + CA84B4D42ED6264F00D19FBE /* Resources */, ); buildRules = ( ); dependencies = ( ); - name = Encapp; + name = Encapp.x264; packageProductDependencies = ( - CAAB92F1292D2ADF009009B2 /* SwiftProtobuf */, - CAAB92F3292D2ADF009009B2 /* SwiftProtobufPluginLibrary */, + CA84B4BC2ED6264F00D19FBE /* SwiftProtobuf */, + CA84B4BE2ED6264F00D19FBE /* SwiftProtobufPluginLibrary */, ); productName = Encapp; - productReference = CAAB92C2292D2ABB009009B2 /* Encapp.app */; + productReference = CA84B4DA2ED6264F00D19FBE /* Encapp.x264.app */; productType = "com.apple.product-type.application"; }; - CAAB92D2292D2ABD009009B2 /* EncappTests */ = { + CAAB92C1292D2ABB009009B2 /* Encapp */ = { isa = PBXNativeTarget; - buildConfigurationList = CAAB92EA292D2ABD009009B2 /* Build configuration list for PBXNativeTarget "EncappTests" */; + buildConfigurationList = CAAB92E7292D2ABD009009B2 /* Build configuration list for PBXNativeTarget "Encapp" */; buildPhases = ( - CAAB92CF292D2ABD009009B2 /* Sources */, - CAAB92D0292D2ABD009009B2 /* Frameworks */, - CAAB92D1292D2ABD009009B2 /* Resources */, + CAAB92BE292D2ABB009009B2 /* Sources */, + CAAB92BF292D2ABB009009B2 /* Frameworks */, + CAAB92C0292D2ABB009009B2 /* Resources */, ); buildRules = ( ); dependencies = ( - CAAB92D5292D2ABD009009B2 /* PBXTargetDependency */, ); - name = EncappTests; + name = Encapp; packageProductDependencies = ( - CA8256F5293E7BEB0082B2BE /* SwiftProtobuf */, - CA8256F7293E7BEB0082B2BE /* SwiftProtobufPluginLibrary */, + CAAB92F1292D2ADF009009B2 /* SwiftProtobuf */, + CAAB92F3292D2ADF009009B2 /* SwiftProtobufPluginLibrary */, ); - productName = EncappTests; - productReference = CAAB92D3292D2ABD009009B2 /* EncappTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; + productName = Encapp; + productReference = CAAB92C2292D2ABB009009B2 /* Encapp.app */; + productType = "com.apple.product-type.application"; }; CAAB92DC292D2ABD009009B2 /* EncappUITests */ = { isa = PBXNativeTarget; @@ -253,10 +278,6 @@ CAAB92C1292D2ABB009009B2 = { CreatedOnToolsVersion = 14.0; }; - CAAB92D2292D2ABD009009B2 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = CAAB92C1292D2ABB009009B2; - }; CAAB92DC292D2ABD009009B2 = { CreatedOnToolsVersion = 14.0; TestTargetID = CAAB92C1292D2ABB009009B2; @@ -280,26 +301,28 @@ projectRoot = ""; targets = ( CAAB92C1292D2ABB009009B2 /* Encapp */, - CAAB92D2292D2ABD009009B2 /* EncappTests */, CAAB92DC292D2ABD009009B2 /* EncappUITests */, + CA84B4BB2ED6264F00D19FBE /* Encapp.x264 */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - CAAB92C0292D2ABB009009B2 /* Resources */ = { + CA84B4D42ED6264F00D19FBE /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - CAAB92CE292D2ABC009009B2 /* Preview Assets.xcassets in Resources */, - CAAB92CA292D2ABC009009B2 /* Assets.xcassets in Resources */, + CA84B4D52ED6264F00D19FBE /* Preview Assets.xcassets in Resources */, + CA84B4D62ED6264F00D19FBE /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - CAAB92D1292D2ABD009009B2 /* Resources */ = { + CAAB92C0292D2ABB009009B2 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + CAAB92CE292D2ABC009009B2 /* Preview Assets.xcassets in Resources */, + CAAB92CA292D2ABC009009B2 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -313,6 +336,29 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + CA84B4BF2ED6264F00D19FBE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CA84B4C02ED6264F00D19FBE /* FrameInfo.swift in Sources */, + CA84B4C12ED6264F00D19FBE /* ListProperties.swift in Sources */, + CA84B4C22ED6264F00D19FBE /* EncappMain.swift in Sources */, + CA84B4C32ED6264F00D19FBE /* ContentView.swift in Sources */, + CA84B4C42ED6264F00D19FBE /* Encoder.swift in Sources */, + CA84B4C52ED6264F00D19FBE /* LocalLogger.swift in Sources */, + CA84B4C62ED6264F00D19FBE /* Utils.swift in Sources */, + CA84B4C72ED6264F00D19FBE /* FileHandling.swift in Sources */, + CA84B4C82ED6264F00D19FBE /* EncappApp.swift in Sources */, + CA84B4C92ED6264F00D19FBE /* TestRunner.swift in Sources */, + CA84B4CA2ED6264F00D19FBE /* Statistics.swift in Sources */, + CA84B4CB2ED6264F00D19FBE /* tests.pb.swift in Sources */, + CA84B4CC2ED6264F00D19FBE /* X264Encoder.swift in Sources */, + CA84B4CD2ED6264F00D19FBE /* CodecHelper.swift in Sources */, + CA84B4CE2ED6264F00D19FBE /* Decoder.swift in Sources */, + CA84B4CF2ED6264F00D19FBE /* JsonStats.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CAAB92BE292D2ABB009009B2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -335,22 +381,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - CAAB92CF292D2ABD009009B2 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CAAB9304292E92EC009009B2 /* Utils.swift in Sources */, - CAAB931129395655009009B2 /* TestRunner.swift in Sources */, - CAAB9301292E7C40009009B2 /* Encoder.swift in Sources */, - CAAB92FB292D380F009009B2 /* ListProperties.swift in Sources */, - CAAB930E29392CC8009009B2 /* JsonStats.swift in Sources */, - CAAB930B293911E8009009B2 /* FrameInfo.swift in Sources */, - CAAB9308293910D9009009B2 /* Statistics.swift in Sources */, - CAAB9314293A7478009009B2 /* CodecHelper.swift in Sources */, - CAAB92FE292D7A44009009B2 /* FileHandling.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; CAAB92D9292D2ABD009009B2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -361,11 +391,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - CAAB92D5292D2ABD009009B2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = CAAB92C1292D2ABB009009B2 /* Encapp */; - targetProxy = CAAB92D4292D2ABD009009B2 /* PBXContainerItemProxy */; - }; CAAB92DF292D2ABD009009B2 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = CAAB92C1292D2ABB009009B2 /* Encapp */; @@ -374,6 +399,144 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + CA84B4D82ED6264F00D19FBE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = Encapp/Encapp.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_ASSET_PATHS = "\"Encapp/Preview Content\""; + DEVELOPMENT_TEAM = PWNNZ9S7WJ; + ENABLE_APP_SANDBOX = YES; + ENABLE_FILE_ACCESS_DOWNLOADS_FOLDER = readwrite; + ENABLE_FILE_ACCESS_MOVIES_FOLDER = readwrite; + ENABLE_FILE_ACCESS_MUSIC_FOLDER = readwrite; + ENABLE_FILE_ACCESS_PICTURE_FOLDER = readwrite; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_INCOMING_NETWORK_CONNECTIONS = YES; + ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; + ENABLE_PREVIEWS = YES; + ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; + ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; + ENABLE_RESOURCE_ACCESS_CALENDARS = NO; + ENABLE_RESOURCE_ACCESS_CAMERA = NO; + ENABLE_RESOURCE_ACCESS_CONTACTS = NO; + ENABLE_RESOURCE_ACCESS_LOCATION = NO; + ENABLE_RESOURCE_ACCESS_PRINTING = NO; + ENABLE_RESOURCE_ACCESS_USB = YES; + ENABLE_USER_SELECTED_FILES = readwrite; + "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = "X264=1"; + GENERATE_INFOPLIST_FILE = YES; + "HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/../modules/x264/"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; + "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/../modules/x264", + ); + MACOSX_DEPLOYMENT_TARGET = 12.3; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = Meta.Encapp; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = EncappX; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = Encapp; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + "SWIFT_ACTIVE_COMPILATION_CONDITIONS[arch=*]" = X264; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + "USER_HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/../modules/x264/"; + }; + name = Debug; + }; + CA84B4D92ED6264F00D19FBE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = Encapp/Encapp.entitlements; + CODE_SIGN_IDENTITY = "-"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_ASSET_PATHS = "\"Encapp/Preview Content\""; + DEVELOPMENT_TEAM = PWNNZ9S7WJ; + ENABLE_APP_SANDBOX = YES; + ENABLE_FILE_ACCESS_DOWNLOADS_FOLDER = readwrite; + ENABLE_FILE_ACCESS_MOVIES_FOLDER = readwrite; + ENABLE_FILE_ACCESS_MUSIC_FOLDER = readwrite; + ENABLE_FILE_ACCESS_PICTURE_FOLDER = readwrite; + ENABLE_INCOMING_NETWORK_CONNECTIONS = YES; + ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; + ENABLE_PREVIEWS = YES; + ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; + ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; + ENABLE_RESOURCE_ACCESS_CALENDARS = NO; + ENABLE_RESOURCE_ACCESS_CAMERA = NO; + ENABLE_RESOURCE_ACCESS_CONTACTS = NO; + ENABLE_RESOURCE_ACCESS_LOCATION = NO; + ENABLE_RESOURCE_ACCESS_PRINTING = NO; + ENABLE_RESOURCE_ACCESS_USB = YES; + ENABLE_USER_SELECTED_FILES = readwrite; + "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = "X264=1"; + GENERATE_INFOPLIST_FILE = YES; + "HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/../modules/x264/"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; + "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/../modules/x264", + ); + MACOSX_DEPLOYMENT_TARGET = 12.3; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = Meta.Encapp; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = EncappX; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = Encapp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + "SWIFT_ACTIVE_COMPILATION_CONDITIONS[arch=*]" = X264; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + "USER_HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/../modules/x264/"; + }; + name = Release; + }; CAAB92E5292D2ABD009009B2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -426,6 +589,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + "HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/include"; IPHONEOS_DEPLOYMENT_TARGET = 14.5; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -434,7 +598,9 @@ SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos"; SUPPORTS_MACCATALYST = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + "SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = ObjC/X264WrapperBridge.h; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + "USER_HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/include"; }; name = Debug; }; @@ -484,6 +650,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + "HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/include"; IPHONEOS_DEPLOYMENT_TARGET = 14.5; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -491,7 +658,9 @@ SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos"; SUPPORTS_MACCATALYST = YES; SWIFT_COMPILATION_MODE = wholemodule; + "SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = ObjC/X264WrapperBridge.h; SWIFT_OPTIMIZATION_LEVEL = "-O"; + "USER_HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/include"; }; name = Release; }; @@ -508,10 +677,27 @@ CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"Encapp/Preview Content\""; - DEVELOPMENT_TEAM = HG384GL4RL; + DEVELOPMENT_TEAM = PWNNZ9S7WJ; + ENABLE_APP_SANDBOX = YES; + ENABLE_FILE_ACCESS_DOWNLOADS_FOLDER = readwrite; + ENABLE_FILE_ACCESS_MOVIES_FOLDER = readwrite; + ENABLE_FILE_ACCESS_MUSIC_FOLDER = readwrite; + ENABLE_FILE_ACCESS_PICTURE_FOLDER = readwrite; ENABLE_HARDENED_RUNTIME = YES; + ENABLE_INCOMING_NETWORK_CONNECTIONS = YES; + ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; ENABLE_PREVIEWS = YES; + ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; + ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; + ENABLE_RESOURCE_ACCESS_CALENDARS = NO; + ENABLE_RESOURCE_ACCESS_CAMERA = NO; + ENABLE_RESOURCE_ACCESS_CONTACTS = NO; + ENABLE_RESOURCE_ACCESS_LOCATION = NO; + ENABLE_RESOURCE_ACCESS_PRINTING = NO; + ENABLE_RESOURCE_ACCESS_USB = YES; + ENABLE_USER_SELECTED_FILES = readwrite; GENERATE_INFOPLIST_FILE = YES; + "HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/../modules/x264/"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; @@ -526,10 +712,14 @@ IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/../modules/x264", + ); MACOSX_DEPLOYMENT_TARGET = 12.3; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = Meta.Encapp; - "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = Encapp; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = EncappX; "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = Encapp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -538,6 +728,7 @@ SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + "USER_HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/../modules/x264/"; }; name = Debug; }; @@ -554,9 +745,26 @@ CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"Encapp/Preview Content\""; - DEVELOPMENT_TEAM = HG384GL4RL; + DEVELOPMENT_TEAM = PWNNZ9S7WJ; + ENABLE_APP_SANDBOX = YES; + ENABLE_FILE_ACCESS_DOWNLOADS_FOLDER = readwrite; + ENABLE_FILE_ACCESS_MOVIES_FOLDER = readwrite; + ENABLE_FILE_ACCESS_MUSIC_FOLDER = readwrite; + ENABLE_FILE_ACCESS_PICTURE_FOLDER = readwrite; + ENABLE_INCOMING_NETWORK_CONNECTIONS = YES; + ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; ENABLE_PREVIEWS = YES; + ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; + ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; + ENABLE_RESOURCE_ACCESS_CALENDARS = NO; + ENABLE_RESOURCE_ACCESS_CAMERA = NO; + ENABLE_RESOURCE_ACCESS_CONTACTS = NO; + ENABLE_RESOURCE_ACCESS_LOCATION = NO; + ENABLE_RESOURCE_ACCESS_PRINTING = NO; + ENABLE_RESOURCE_ACCESS_USB = YES; + ENABLE_USER_SELECTED_FILES = readwrite; GENERATE_INFOPLIST_FILE = YES; + "HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/../modules/x264/"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; @@ -571,10 +779,14 @@ IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/../modules/x264", + ); MACOSX_DEPLOYMENT_TARGET = 12.3; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = Meta.Encapp; - "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = Encapp; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = EncappX; "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = Encapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; @@ -582,63 +794,7 @@ SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - CAAB92EB292D2ABD009009B2 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - BUNDLE_LOADER = "$(TEST_HOST)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HG384GL4RL; - "DEVELOPMENT_TEAM[sdk=macosx*]" = HG384GL4RL; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.5; - MACOSX_DEPLOYMENT_TARGET = 12.3; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = Meta.EncappTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Encapp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Encapp"; - }; - name = Debug; - }; - CAAB92EC292D2ABD009009B2 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - BUNDLE_LOADER = "$(TEST_HOST)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HG384GL4RL; - "DEVELOPMENT_TEAM[sdk=macosx*]" = HG384GL4RL; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.5; - MACOSX_DEPLOYMENT_TARGET = 12.3; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = Meta.EncappTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Encapp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Encapp"; + "USER_HEADER_SEARCH_PATHS[arch=*]" = "$(SRCROOT)/../modules/x264/"; }; name = Release; }; @@ -691,29 +847,29 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - CAAB92BD292D2ABB009009B2 /* Build configuration list for PBXProject "Encapp" */ = { + CA84B4D72ED6264F00D19FBE /* Build configuration list for PBXNativeTarget "Encapp.x264" */ = { isa = XCConfigurationList; buildConfigurations = ( - CAAB92E5292D2ABD009009B2 /* Debug */, - CAAB92E6292D2ABD009009B2 /* Release */, + CA84B4D82ED6264F00D19FBE /* Debug */, + CA84B4D92ED6264F00D19FBE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - CAAB92E7292D2ABD009009B2 /* Build configuration list for PBXNativeTarget "Encapp" */ = { + CAAB92BD292D2ABB009009B2 /* Build configuration list for PBXProject "Encapp" */ = { isa = XCConfigurationList; buildConfigurations = ( - CAAB92E8292D2ABD009009B2 /* Debug */, - CAAB92E9292D2ABD009009B2 /* Release */, + CAAB92E5292D2ABD009009B2 /* Debug */, + CAAB92E6292D2ABD009009B2 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - CAAB92EA292D2ABD009009B2 /* Build configuration list for PBXNativeTarget "EncappTests" */ = { + CAAB92E7292D2ABD009009B2 /* Build configuration list for PBXNativeTarget "Encapp" */ = { isa = XCConfigurationList; buildConfigurations = ( - CAAB92EB292D2ABD009009B2 /* Debug */, - CAAB92EC292D2ABD009009B2 /* Release */, + CAAB92E8292D2ABD009009B2 /* Debug */, + CAAB92E9292D2ABD009009B2 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -730,6 +886,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + CA84B4BD2ED6264F00D19FBE /* XCRemoteSwiftPackageReference "swift-protobuf" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-protobuf.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; CAAB92F0292D2ADF009009B2 /* XCRemoteSwiftPackageReference "swift-protobuf" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/apple/swift-protobuf.git"; @@ -741,14 +905,14 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - CA8256F5293E7BEB0082B2BE /* SwiftProtobuf */ = { + CA84B4BC2ED6264F00D19FBE /* SwiftProtobuf */ = { isa = XCSwiftPackageProductDependency; - package = CAAB92F0292D2ADF009009B2 /* XCRemoteSwiftPackageReference "swift-protobuf" */; + package = CA84B4BD2ED6264F00D19FBE /* XCRemoteSwiftPackageReference "swift-protobuf" */; productName = SwiftProtobuf; }; - CA8256F7293E7BEB0082B2BE /* SwiftProtobufPluginLibrary */ = { + CA84B4BE2ED6264F00D19FBE /* SwiftProtobufPluginLibrary */ = { isa = XCSwiftPackageProductDependency; - package = CAAB92F0292D2ADF009009B2 /* XCRemoteSwiftPackageReference "swift-protobuf" */; + package = CA84B4BD2ED6264F00D19FBE /* XCRemoteSwiftPackageReference "swift-protobuf" */; productName = SwiftProtobufPluginLibrary; }; CAAB92F1292D2ADF009009B2 /* SwiftProtobuf */ = { diff --git a/ios/Encapp.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Encapp.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/ios/Encapp.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Encapp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Encapp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000..126666db --- /dev/null +++ b/ios/Encapp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,15 @@ +{ + "originHash" : "9f1e4ec4211205225a9be53f971e143ca4f7b80574f1ff773ebee5bf69ffe8ab", + "pins" : [ + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "2547102afd04fe49f1b286090f13ebce07284980", + "version" : "1.31.1" + } + } + ], + "version" : 3 +} diff --git a/ios/Encapp.xcodeproj/project.xcworkspace/xcuserdata/jblome.xcuserdatad/UserInterfaceState.xcuserstate b/ios/Encapp.xcodeproj/project.xcworkspace/xcuserdata/jblome.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..4dba6e30 Binary files /dev/null and b/ios/Encapp.xcodeproj/project.xcworkspace/xcuserdata/jblome.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/Encapp.xcodeproj/xcshareddata/xcschemes/Encapp test.xcscheme b/ios/Encapp.xcodeproj/xcshareddata/xcschemes/Encapp test.xcscheme new file mode 100644 index 00000000..a4da5f10 --- /dev/null +++ b/ios/Encapp.xcodeproj/xcshareddata/xcschemes/Encapp test.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Encapp.xcodeproj/xcshareddata/xcschemes/Encapp.xcscheme b/ios/Encapp.xcodeproj/xcshareddata/xcschemes/Encapp.xcscheme new file mode 100644 index 00000000..fe4724ea --- /dev/null +++ b/ios/Encapp.xcodeproj/xcshareddata/xcschemes/Encapp.xcscheme @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Encapp.xcodeproj/xcuserdata/jblome.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/ios/Encapp.xcodeproj/xcuserdata/jblome.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 00000000..7b7ee619 --- /dev/null +++ b/ios/Encapp.xcodeproj/xcuserdata/jblome.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Encapp.xcodeproj/xcuserdata/jblome.xcuserdatad/xcschemes/Copy of Copy of Encapp test.xcscheme b/ios/Encapp.xcodeproj/xcuserdata/jblome.xcuserdatad/xcschemes/Copy of Copy of Encapp test.xcscheme new file mode 100644 index 00000000..730cbc13 --- /dev/null +++ b/ios/Encapp.xcodeproj/xcuserdata/jblome.xcuserdatad/xcschemes/Copy of Copy of Encapp test.xcscheme @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Encapp.xcodeproj/xcuserdata/jblome.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/Encapp.xcodeproj/xcuserdata/jblome.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..2ff29ac8 --- /dev/null +++ b/ios/Encapp.xcodeproj/xcuserdata/jblome.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,47 @@ + + + + + SchemeUserState + + Copy of Copy of Encapp test.xcscheme + + orderHint + 3 + + Copy of Encapp test.xcscheme + + orderHint + 2 + + Encapp test.xcscheme_^#shared#^_ + + orderHint + 1 + + Encapp.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + CAAB92C1292D2ABB009009B2 + + primary + + + CAAB92D2292D2ABD009009B2 + + primary + + + CAAB92DC292D2ABD009009B2 + + primary + + + + + diff --git a/ios/Encapp/Encapp.entitlements b/ios/Encapp/Encapp.entitlements index 18aff0ce..852fa1a4 100644 --- a/ios/Encapp/Encapp.entitlements +++ b/ios/Encapp/Encapp.entitlements @@ -4,7 +4,5 @@ com.apple.security.app-sandbox - com.apple.security.files.user-selected.read-only - diff --git a/ios/Encapp/EncappMain.swift b/ios/Encapp/EncappMain.swift index 0eb9a802..c366e1a3 100644 --- a/ios/Encapp/EncappMain.swift +++ b/ios/Encapp/EncappMain.swift @@ -43,6 +43,7 @@ class EncappMain { completion() } else if command.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() == "test" { log.info("Running a test suite.") + let io = FileIO() io.writeData(filename: runningLockName, data: "Running") if CommandLine.arguments.count < 3 { @@ -55,12 +56,22 @@ class EncappMain { log.error("Non existing test file: \(testToRun)") completion() } + var overrideSource = "" + if CommandLine.arguments.count > 3 { + let c2 = CommandLine.arguments[3] as String + if c2 == "-i" { + overrideSource = (CommandLine.arguments[4] as String) + } + } log.info("Start testing: '\(testToRun)'") overview.updateTestsLog(text: "Starting test: '\(testToRun)'") - let runner = TestRunner(filename: testToRun, completion: completion) + let runner = TestRunner(filename: testToRun, input: overrideSource, completion: completion) runner.start() } else if command == "standby" { // This is only to keep the screen on while doing slow io + } else if command == "files" { + let io = FileIO() + io.listFiles() } } diff --git a/ios/Encapp/Encoder.swift b/ios/Encapp/Encoder.swift index 7580ee13..1660f298 100644 --- a/ios/Encapp/Encoder.swift +++ b/ios/Encapp/Encoder.swift @@ -286,6 +286,7 @@ class Encoder { func sleepUntilNextFrame() { + log.debug("*** Sleep until next frame *****") let now = timeStampNs() / 1000000 if lastTimeMs <= 0 { lastTimeMs = now diff --git a/ios/Encapp/TestRunner.swift b/ios/Encapp/TestRunner.swift index da73ea77..e7c7d0bf 100644 --- a/ios/Encapp/TestRunner.swift +++ b/ios/Encapp/TestRunner.swift @@ -9,13 +9,15 @@ import Foundation class TestRunner: Thread { var filename: String + var overrideInput: String? = nil var testsRunning = Array() var isRunning = true var completion: ()->()? - - init(filename: String, completion: @escaping ()->()) { + + init(filename: String, input: String, completion: @escaping ()->()) { self.filename = filename self.completion = completion + self.overrideInput = input } override func main() { // Thread's starting point @@ -27,21 +29,25 @@ class TestRunner: Thread { log.info("Starting threaded test") let io = FileIO() let testsuite = io.readTestDefinition(inputfile: filename) - log.info("Test definition: \(testsuite)") + if testsuite.test.count == 0 { log.error("No test, probably faulty path or definition") return } - + var counter = 1 for test in testsuite.test { let descr = "** Running \(counter)/\(testsuite.test.count), test: \(test.common.id)" log.info(descr) overview.updateTestsLog(text: descr) + var test_ = test + if overrideInput!.count > 0 { + test_.input.filepath = overrideInput! + } counter += 1 //TODO: add start sync - if test.hasParallel { - for parallel in test.parallel.test { + if test_.hasParallel { + for parallel in test_.parallel.test { let task = RunSingleTest(test: parallel, completion: completion) testsRunning.append(task) @@ -49,7 +55,7 @@ class TestRunner: Thread { task.start() } } - let task = RunSingleTest(test: test, completion: completion) + let task = RunSingleTest(test: test_, completion: completion) log.info("** start blocking") testsRunning.append(task) task.start() @@ -100,18 +106,29 @@ class TestRunner: Thread { } else { //TODO: fix later, for now simple things log.info("Start encoding test: \(test.common.id)") - let encoder = Encoder(test: test) + // Check the encoder if x264 choose the x264 encoder (duh) + let encoder: Encoder + if test.configure.codec.contains("x264") { + #if X264 + encoder = X264Encoder(test: test) + #else + log.error("X264 build is not included in this build") + throw EncappErrors.x264NotAvailable + #endif + } else { + encoder = Encoder(test: test) + } let result = try encoder.Encode() statistics = encoder.statistics log.info("\(result)") log.info("Done testing: ") } - + done = true + self.completion(self) } catch { log.error("Error running single test") } - done = true - self.completion(self) + sem.signal() } diff --git a/ios/Encapp/X264Encoder.swift b/ios/Encapp/X264Encoder.swift new file mode 100644 index 00000000..86055471 --- /dev/null +++ b/ios/Encapp/X264Encoder.swift @@ -0,0 +1,513 @@ +// +// Encoder.swift +// Encapp +// +// Created by Johan Blome on 11/23/22. +// + +import Foundation +import VideoToolbox +import AVFoundation + +typealias x264_t_ptr = OpaquePointer + +class X264Encoder: Encoder{ + var x264Encoder: x264_t_ptr? + var inputBuffer: UnsafeMutableRawPointer? + var x264InputFrame: UnsafeMutablePointer? + var x264OutputFrame: UnsafeMutablePointer? + var yPlaneSize: Int! + var uvPlaneSize: Int! + var formatDescription: CMFormatDescription! + + override init(test: Test){ + super.init(test: test) + } + + func parseConfiguration(test: Test, params: inout x264_param_t) -> Int { + var preset = "fast" + var tune: String? = nil + + for param in test.configure.parameter { + if param.key == "preset" { + preset = param.value + log.debug("Set preset: \(preset)") + } else if param.key == "tune" { + if param.value != "none" { + tune = param.value + log.debug("Set tune: \(tune)") + } + } + } + + + let result = x264_param_default_preset(¶ms, preset, tune) + if result < 0 { + log.error("Failed to set preset and tune") + } else { + log.debug("Preset and tune set successfully") + } + + + // Logging, skip unless needed. + //params.pointee.i_csp = X264_CSP_I420 + //params.pointee.p_log_private = nil + //params.pointee.i_log_level = Int32(X264_LOG_DEBUG) // Or another log level + //x264_set_log_callback(params) + + return 0 + } + + // + override func Encode() throws -> String { + log.info("Starting x264 encoder") + statistics = Statistics(description: "raw encoder", test: definition) + if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first { + log.info("Encode, current test definition = \n\(definition)") + + // Check input + let resolution = splitX(text: definition.input.resolution) + let sourceWidth = resolution[0] + let sourceHeight = resolution[1] + // TODO: it seems the encoder is expecting aligned planes + let width = Int((resolution[0] >> 1) << 1) + let height = Int((resolution[1] >> 1) << 1) + inputFrameRate = (definition.input.hasFramerate) ? definition.input.framerate: 30.0 + outputFrameRate = (definition.configure.hasFramerate) ? definition.configure.framerate: inputFrameRate + + if inputFrameRate <= 0 { + inputFrameRate = 30.0 + } + if outputFrameRate <= 0 { + outputFrameRate = 30.0 + } + keepInterval = inputFrameRate / outputFrameRate; + frameDurationUsec = calculateFrameTimingUsec(frameRate: outputFrameRate); + inputFrameDurationUsec = calculateFrameTimingUsec(frameRate: inputFrameRate); + inputFrameDurationMs = Float(frameDurationUsec) / 1000.0 + scale = 1000_000 //should be 90000? + statistics.setTimescale(timeScale: scale) + frameDurationUsec = calculateFrameTimingUsec(frameRate: outputFrameRate); + frameDurationMs = Float(frameDurationUsec) / 1000.0 + frameDurationSec = Float(frameDurationUsec) / 1000_000.0 + frameDurationCMTime = CMTime.init(value: Int64(1.0/30.0 * Double(scale)), timescale: CMTimeScale(scale)) + + // Codec type + if !definition.configure.hasCodec { + log.error("No codec defined") + return "" + } + let props = ListProps() + self.inputBuffer = UnsafeMutableRawPointer.allocate(byteCount: width * height * 3/2, alignment: 16) // Really 1.5, no odd ones + self.yPlaneSize = width * height + self.uvPlaneSize = width * height / 4 + statistics.setEncoderName(encoderName: "x264") + + + log.debug(String(format: "Create x264 encoder with %dx%d", width, height)) + var params = UnsafeMutablePointer.allocate(capacity: 1) + //x264_param_default(params) + if parseConfiguration(test: definition, params: ¶ms.pointee) < 0 { + log.debug("Failed to set preset ans tune") + } + + params.pointee.i_width = Int32(width) + params.pointee.i_height = Int32(height) + var frameRate: Float = 30.0 + if definition.configure.hasFramerate { + frameRate = definition.configure.framerate + } else if definition.input.hasFramerate { + frameRate = definition.input.framerate + } + params.pointee.i_fps_num = UInt32(frameRate) + params.pointee.i_fps_den = 1 + + // TODO: Bitrate mode is a mess, to bps + params.pointee.rc.i_bitrate = Int32(magnitudeToInt(stringValue: definition.configure.bitrate)/1000) //x264 is using kbps + log.debug("Bitrate set: \(definition.configure.bitrate) to \(params.pointee.rc.i_bitrate) kbps") + + let bitrate_mode = definition.configure.bitrateMode + if bitrate_mode == Configure.BitrateMode.cbr { + params.pointee.rc.i_rc_method = X264_RC_ABR + params.pointee.rc.i_vbv_max_bitrate = params.pointee.rc.i_bitrate + params.pointee.rc.i_vbv_buffer_size = params.pointee.rc.i_vbv_max_bitrate * 2 + } else if bitrate_mode == Configure.BitrateMode.cq { + // map 0-100 to 0-51 + params.pointee.rc.i_rc_method = X264_RC_CRF + params.pointee.rc.i_vbv_max_bitrate = params.pointee.rc.i_bitrate + params.pointee.rc.i_vbv_buffer_size = params.pointee.rc.i_vbv_max_bitrate * 2 + params.pointee.rc.f_rf_constant = Float(definition.configure.quality) / 100.0 * 51.0 + } else { + // vbr or crf in this case + params.pointee.rc.i_rc_method = X264_RC_CRF + params.pointee.rc.i_vbv_max_bitrate = params.pointee.rc.i_bitrate + params.pointee.rc.i_vbv_buffer_size = params.pointee.rc.i_vbv_max_bitrate * 2 + params.pointee.rc.f_rf_constant = 18 + params.pointee.rc.f_rf_constant_max = 25 + } + // i frame interval is in seconds on Android and in frames here, translate + params.pointee.i_frame_reference = Int32(frameRate) + + //TODO: default? + params.pointee.i_threads = 0 + + params.pointee.i_timebase_den = 1 + params.pointee.i_timebase_num = 1000000 + + self.x264Encoder = x264_encoder_open_165(¶ms.pointee) + self.x264InputFrame = UnsafeMutablePointer.allocate(capacity: 1) + self.x264OutputFrame = UnsafeMutablePointer.allocate(capacity: 1) + x264_picture_init(x264InputFrame) + x264_picture_alloc(x264InputFrame, X264_CSP_I420, Int32(sourceWidth), Int32(sourceHeight)) + x264_picture_init(x264OutputFrame) + + + let frameSize = Int(Float(sourceWidth) * Float(sourceHeight) * 1.5) + // Filehandling + let fileURL = dir.appendingPathComponent(definition.input.filepath) + if FileManager.default.fileExists(atPath: fileURL.path) { + log.info("Input media file: \(fileURL.path)") + } else { + log.error("Media file: \(fileURL.path) doe not exist") + return "Error: no media file" + } + let outputURL = dir.appendingPathComponent("\(statistics.id!).mov") + let outputPath = outputURL.path + try? FileManager.default.removeItem(atPath: outputPath) + + // Nil for encoded data, only mov works + let outputWriter = try AVAssetWriter(outputURL: outputURL, fileType: AVFileType.mov) + outputWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: nil) + outputWriter.add(outputWriterInput) + + outputWriter.startWriting() + outputWriter.startSession(atSourceTime: CMTime.zero) + + var splitname = definition.input.filepath.components(separatedBy: "/") + statistics.setSourceFile(filename: splitname[splitname.count - 1]) + splitname = outputPath.components(separatedBy: "/") + statistics.setEncodedFile(filename: splitname[splitname.count - 1]) + var lastNow = timeStampNs() + let realtime = definition.input.realtime + if var stream: InputStream = InputStream(fileAtPath: fileURL.path) { + stream.open() + statistics.start() + + while (!inputDone) {//} || !outputDone) { + if (inputFrameCounter % 100 == 0) { + log.info(""" + \(definition.common.id) - BufferEncoder: frames: \(framesAdded) \ + input frames: \(inputFrameCounter) current loop: \(currentLoop) current time: \(currentTimeSec) + """) + let now = timeStampNs() + log.info("time since last time \((Float(now)-Float(lastNow))/1000_000_000.0)") + lastNow = now + } + if doneReading(test: definition, stream: stream, frame: framesAdded, time: currentTimeSec, loop: false) { + inputDone = true + } + + // PUSH + let size = queueInputBuffer(stream: stream, frameSize: frameSize, realtime: realtime) + if size == -2 { + continue; + } else if (size <= 0 ) { + // restart loop + stream.close() + currentLoop += 1 + + if doneReading(test: definition, stream: stream, frame: framesAdded, time: currentTimeSec, loop: true) { + inputDone = true; + } else { + log.info(" *********** OPEN FILE AGAIN *******"); + stream = InputStream(fileAtPath: fileURL.path)! + stream.open() + log.info("*** Loop ended start \(currentLoop) ***"); + } + } + } + + statistics.stop() + //Flush + let framePts = computePresentationTimeUsec(frameIndex: inputFrameCounter, frameTimeUsec: inputFrameDurationUsec, offset: Int64(pts)) + let lastTime = CMTime.init(value: Int64(framePts), timescale: CMTimeScale(scale)) + outputWriterInput.markAsFinished() + log.info("Wait for all pending frames") + sleep(1) + log.info("Call writer finish") + outputWriter.finishWriting { + sleep(1) + } + + while outputWriter.status == AVAssetWriter.Status.writing { + sleep(1) + } + + stream.close() + } + x264_picture_clean(x264InputFrame) + x264InputFrame!.deallocate() + x264OutputFrame!.deallocate() + } + log.info("Done, leaving encoder, encoded: \(statistics.encodedFrames.count)") + log.debug("Average bitrate: \(Float(statistics.getAverageBitrate())) kbps") + return "" + } + + func convertAnnexBToAVCC(nals: [x264_nal_t]) -> Data { + var avccData = Data() + for nal in nals { + var length = UInt32(nal.i_payload).bigEndian + avccData.append(Data(bytes: &length, count: 4)) + avccData.append(Data(bytes: nal.p_payload, count: Int(nal.i_payload))) + } + return avccData + } + + func stripStartCode(_ payload: UnsafePointer, length: Int) -> [UInt8] { + var offset = 0 + // Check for 4-byte start code + if length > 4 && payload[0] == 0 && payload[1] == 0 && payload[2] == 0 && payload[3] == 1 { + offset = 4 + } else if length > 3 && payload[0] == 0 && payload[1] == 0 && payload[2] == 1 { + offset = 3 + } + return Array(UnsafeBufferPointer(start: payload + offset, count: length - offset)) + } + + func createCMSampleBuffer(from avccData: Data, pts: CMTime, dts: CMTime, formatDesc: CMFormatDescription) -> CMSampleBuffer? { + var blockBuffer: CMBlockBuffer? + let status = CMBlockBufferCreateWithMemoryBlock( + allocator: kCFAllocatorDefault, + memoryBlock: UnsafeMutableRawPointer(mutating: (avccData as NSData).bytes), + blockLength: avccData.count, + blockAllocator: kCFAllocatorNull, + customBlockSource: nil, + offsetToData: 0, + dataLength: avccData.count, + flags: 0, + blockBufferOut: &blockBuffer + ) + guard status == kCMBlockBufferNoErr, let blockBuffer = blockBuffer else { return nil } + var sampleBuffer: CMSampleBuffer? + let sampleSizes = [avccData.count] + let err = CMSampleBufferCreate( + allocator: kCFAllocatorDefault, + dataBuffer: blockBuffer, + dataReady: true, + makeDataReadyCallback: nil, + refcon: nil, + formatDescription: formatDesc, + sampleCount: 1, + sampleTimingEntryCount: 1, + sampleTimingArray: [CMSampleTimingInfo(duration: .invalid, presentationTimeStamp: pts, decodeTimeStamp: dts)], + sampleSizeEntryCount: 1, + sampleSizeArray: sampleSizes, + sampleBufferOut: &sampleBuffer + ) + return (err == noErr) ? sampleBuffer : nil + } + + func writeData(sampleBuffer: CMSampleBuffer) -> Void { + let size = sampleBuffer.totalSampleSize + var buffer = [UInt8](repeating: 0, count: size) + var bufferPtr: UnsafeMutablePointer? + let status = buffer.withUnsafeMutableBytes { tmp in + CMBlockBufferAccessDataBytes( + (sampleBuffer.dataBuffer)!, + atOffset: 0, + length: size, + temporaryBlock: tmp.baseAddress!, + returnedPointerOut: &bufferPtr + ) + } + guard status == noErr else { + log.error("Failed to get base address for blockbuffer") + return + } + if let attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, createIfNecessary: true) { + let rawDic: UnsafeRawPointer = CFArrayGetValueAtIndex(attachments, 0) + let dic: CFDictionary = Unmanaged.fromOpaque(rawDic).takeUnretainedValue() + + //let keyFrame = !CFDictionaryContainsKey(dic, Unmanaged.passUnretained(kCMSampleAttachmentKey_NotSync).toOpaque()) + currentTimeSec = Float(sampleBuffer.presentationTimeStamp.value) / Float(scale) + framesAdded += 1 + + if outputWriterInput.isReadyForMoreMediaData { + outputWriterInput.append(sampleBuffer) + } else { + log.error("Writer not ready for input") + } + } + } + + + + + func queueInputBuffer(stream: InputStream, frameSize: Int, realtime: Bool) -> Int { + if !stream.hasBytesAvailable { + log.info("Nothing more to read") + return -1; + } + + var read = stream.read(inputBuffer!, maxLength: frameSize) + if read == 0 { + log.info("End of stream") + return -1; + } + + + var timeInfo = CMSampleTimingInfo() + let framePts = computePresentationTimeUsec(frameIndex: inputFrameCounter, frameTimeUsec: inputFrameDurationUsec, offset: Int64(pts)) + setRuntimeParameters(frame: Int64(inputFrameCounter)); + dropNext = dropFrame(frame: Int64(inputFrameCounter)) + updateDynamicFramerate(frame: Int64(inputFrameCounter)); + + if !dropNext { + dropNext = dropFromDynamicFramerate(frame: inputFrameCounter, keepInterval: keepInterval); + } + inputFrameCounter += 1 + if dropNext { + dropNext = false + skipped += 1 + read = -2 //TODO: enum + } else if (read == frameSize) { + timeInfo.presentationTimeStamp = CMTime.init(value: Int64(framePts), timescale: CMTimeScale(scale)) + timeInfo.duration = CMTime.init(value: Int64(frameDurationUsec), timescale: CMTimeScale(scale)) + timeInfo.decodeTimeStamp = timeInfo.presentationTimeStamp + + if realtime { + sleepUntilNextFrame() + } + + guard let dataloc = inputBuffer else { + log.error("No data from stream") + return -1; + } + + // Copy Y plane + memcpy(x264InputFrame!.pointee.img.plane.0, dataloc, yPlaneSize) + + // Copy U plane + let uPointer = dataloc.advanced(by: yPlaneSize) + memcpy(x264InputFrame!.pointee.img.plane.1, uPointer, uvPlaneSize) + + // Copy V plane + let vPointer = dataloc.advanced(by: yPlaneSize + uvPlaneSize) + memcpy(x264InputFrame!.pointee.img.plane.2, vPointer, uvPlaneSize) + + x264InputFrame!.pointee.i_pts = Int64(framePts) + var nalPtr: UnsafeMutablePointer? = nil + var piNal: Int32 = 0 + // Write nals to file or process + statistics.startEncoding(pts: Int64(framePts), originalFrame: inputFrameCounter) + let bytes = x264_encoder_encode(self.x264Encoder, &nalPtr, &piNal, x264InputFrame!, x264OutputFrame!) + + + var keyFrame = false + if piNal > 0 { + let nals = Array(UnsafeBufferPointer(start: nalPtr, count: Int(piNal))) + let avcc = convertAnnexBToAVCC(nals: nals) + let pts = CMTime(value: x264OutputFrame!.pointee.i_pts, timescale: CMTimeScale(scale)) + let dts = CMTime(value: x264OutputFrame!.pointee.i_dts, timescale: CMTimeScale(scale)) + + if formatDescription == nil { + // Looks for sps and ppa and create format + let nals = Array(UnsafeBufferPointer(start: nalPtr, count: Int(piNal))) + var sps: [UInt8] = [] + var pps: [UInt8] = [] + var status: OSStatus = -1 + for nal in nals { + if nal.i_type == 7 { // SPS + sps = stripStartCode(nal.p_payload, length: Int(nal.i_payload)) + } else if nal.i_type == 8 { // PPS + pps = stripStartCode(nal.p_payload, length: Int(nal.i_payload)) + } + } + + // Only proceed if both SPS and PPS are found + guard !sps.isEmpty, !pps.isEmpty else { + print("SPS or PPS not found") + return -1 + } + sps.withUnsafeBytes { spsBuffer in + pps.withUnsafeBytes { ppsBuffer in + let parameterSetPointers: [UnsafePointer] = [ + spsBuffer.baseAddress!.assumingMemoryBound(to: UInt8.self), + ppsBuffer.baseAddress!.assumingMemoryBound(to: UInt8.self) + ] + let parameterSetSizes: [Int] = [sps.count, pps.count] + status = CMVideoFormatDescriptionCreateFromH264ParameterSets( + allocator: kCFAllocatorDefault, + parameterSetCount: 2, + parameterSetPointers: parameterSetPointers, + parameterSetSizes: parameterSetSizes, + nalUnitHeaderLength: 4, + formatDescriptionOut: &formatDescription + ) + } + } + + if status != noErr { + log.error("Failed to extract sps/pps") + return -1 + } + } + let buffer = createCMSampleBuffer(from: avcc, pts: pts, dts: dts, formatDesc: formatDescription) + keyFrame = (((x264OutputFrame!.pointee.i_type == X264_TYPE_AUTO || x264OutputFrame!.pointee.i_type == X264_TYPE_IDR) ? 1 : 0) != 0) + statistics.stopEncoding(pts: framePts, size: Int64(bytes), isKeyFrame: keyFrame) + writeData(sampleBuffer: buffer!) + + } else { + log.debug("No nals") + } + + lastPts = timeInfo.presentationTimeStamp + + } else { + log.info("Could not read all - only: \(read)") + read = -1 + } + + return read + } + + + + override func setRuntimeParameters(frame: Int64) { + if !definition.hasRuntime { + return + } + + for setting in definition.runtime.videoBitrate { + if setting.framenum == frame { + setBitrate(compSession: compSession, bps: magnitudeToInt(stringValue: setting.bitrate), cbr: false) + } + } + + for framenum in definition.runtime.requestSync { + if framenum == frame { + let status = VTSessionSetProperty(compSession, key: kVTEncodeFrameOptionKey_ForceKeyFrame, value: true as CFBoolean) + if status != 0 { + log.error("failed force key frame, status: \(status)") + } + } + } + + for setting in definition.runtime.parameter { + if setting.framenum == frame { + switch setting.type { + case DataValueType.floatType: + break + case DataValueType.intType: + break + case DataValueType.longType: + break + case DataValueType.stringType: + break + } + } + } + } + +} diff --git a/ios/Encapp/debug.txt b/ios/Encapp/debug.txt new file mode 100644 index 00000000..747fe2ac --- /dev/null +++ b/ios/Encapp/debug.txt @@ -0,0 +1,3 @@ +Command line invocation: + /Users/jblome/Downloads/Xcode.app/Contents/Developer/usr/bin/xcodebuild -showBuildSettings -configuration Debug + diff --git a/ios/Encapp/profile.txt b/ios/Encapp/profile.txt new file mode 100644 index 00000000..8b541746 --- /dev/null +++ b/ios/Encapp/profile.txt @@ -0,0 +1,3 @@ +Command line invocation: + /Users/jblome/Downloads/Xcode.app/Contents/Developer/usr/bin/xcodebuild -showBuildSettings -configuration Profile + diff --git a/ios/Encapp/utils/CodecHelper.swift b/ios/Encapp/utils/CodecHelper.swift index fc9e722e..24c9826e 100644 --- a/ios/Encapp/utils/CodecHelper.swift +++ b/ios/Encapp/utils/CodecHelper.swift @@ -21,7 +21,7 @@ func logVTSessionProperties(statistics: Statistics, compSession: VTSession) { if d?["PropertyType"]! as? String == "Number"{ var propval: CFNumber! status = VTSessionCopyProperty(compSession, key: key as! CFString, allocator: nil, valueOut: &propval) - if status == noErr{ + if status == noErr && propval != nil { log.debug("---val: \(propval.debugDescription)") statistics.addProp(name: key as! String, val: "\(propval!)") } diff --git a/ios/Encapp/utils/FileHandling.swift b/ios/Encapp/utils/FileHandling.swift index d69aad45..7324fc3b 100644 --- a/ios/Encapp/utils/FileHandling.swift +++ b/ios/Encapp/utils/FileHandling.swift @@ -74,10 +74,11 @@ struct FileIO { var text = "" do { text = try String(contentsOf: fileURL, encoding: .utf8) + log.info("\(text)") tests = try TestSuite.init(textFormatString: text) } catch {/* error handling here */ - log.error("Failed to read data: \(text)") + log.error("Failed to read data: \(text), missmatch in protobuf?") } } @@ -160,4 +161,22 @@ struct FileIO { } return false } + + func listFiles() { + let fileManager = FileManager.default + if let dir = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first { + do { + let directoryContents = try fileManager.contentsOfDirectory( + at: dir, + includingPropertiesForKeys: nil + , options: .skipsHiddenFiles) + + for d in directoryContents { + log.debug(d.absoluteString) + } + } catch { + log.error("Failed to read directory contents") + } + } + } } diff --git a/ios/Encapp/utils/Statistics.swift b/ios/Encapp/utils/Statistics.swift index 95257e2b..c6284bdb 100644 --- a/ios/Encapp/utils/Statistics.swift +++ b/ios/Encapp/utils/Statistics.swift @@ -24,6 +24,7 @@ class Statistics { var decodedFrames: Array var frameLock = NSLock() var props: Array + var timeScale_ = 1 as Int init(description: String, test: Test) { self.description = description @@ -112,14 +113,31 @@ class Statistics { return frameInfo } - func getAverageBitrate(frames: Array)->Int { - return 0 + // bps + func getAverageBitrate()->Int64 { + let frames = encodedFrames + if frames.count == 0 { + return 0 + } + var sum: Int64 = 0 + for info in frames { + sum += Int64(info.size!) + } + let bps0 = frames[0].pts + let bpsN = frames[frames.count-1].pts + let duration: Int64 = (bpsN - bps0)/Int64(timeScale_) + log.debug("duration: \(duration)") + return sum/duration } func getProcessingTime() -> Int64 { return (stopTime! - startTime!); } + func setTimescale(timeScale: Int) { + timeScale_ = timeScale + } + func setEncoderName(encoderName: String) { self.encoderName = encoderName } @@ -201,7 +219,7 @@ class Statistics { test: jtest, environment: environment, codec: encoderName, - meanbitrate: getAverageBitrate(frames: encodedFrames), + meanbitrate: Int(getAverageBitrate()), date: DateFormatter().string(from: date!), encapp_version: appVersion, proctime: getProcessingTime(), diff --git a/ios/Encapp/utils/Utils.swift b/ios/Encapp/utils/Utils.swift index 91a3505a..65c439a6 100644 --- a/ios/Encapp/utils/Utils.swift +++ b/ios/Encapp/utils/Utils.swift @@ -87,7 +87,7 @@ func doneReading(test: Test, stream: InputStream?, frame: Int, time: Float, loop if (test.input.hasPlayoutFrames && test.input.playoutFrames > 0) { // 2. stop the reader based on explicit playout frames parameter: // stop if we reached the explicit playout frames - if (frame >= test.input.playoutFrames) { + if (frame >= test.input.playoutFrames) { return true } } @@ -145,3 +145,7 @@ func sleepUntilNextFrame(lastTimeMs: Int64, frameDurationMs: Double) -> Int64 { return updatedLastTime } +enum EncappErrors: Error { + case x264NotAvailable +} + diff --git a/ios/ObjC/.DS_Store b/ios/ObjC/.DS_Store new file mode 100644 index 00000000..3f99181a Binary files /dev/null and b/ios/ObjC/.DS_Store differ diff --git a/ios/ObjC/X264Wrapper.h b/ios/ObjC/X264Wrapper.h new file mode 100644 index 00000000..168fb001 --- /dev/null +++ b/ios/ObjC/X264Wrapper.h @@ -0,0 +1,35 @@ +#import +#import "x264.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface X264Wrapper : NSObject + +/* +// Encoder lifecycle +- (instancetype)initWithParams:(x264_param_t *)params; +- (void)close; + +// Encoding +- (int)encodeFrame:(x264_picture_t *)picIn + picOut:(x264_picture_t *)picOut + nals:(x264_nal_t *_Nonnull*_Nonnull)ppNal + nalCount:(int *)piNal; + +// Headers +- (int)getHeaders:(x264_nal_t *_Nonnull*_Nonnull)ppNal nalCount:(int *)piNal; + +// Intra refresh +- (void)intraRefresh; + +// Invalidate reference +- (int)invalidateReference:(int64_t)pts; + +// Delayed frames +- (int)delayedFrames; +- (int)maximumDelayedFrames; +*/ + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/ObjC/X264WrapperBridge.h b/ios/ObjC/X264WrapperBridge.h new file mode 100644 index 00000000..ac44b012 --- /dev/null +++ b/ios/ObjC/X264WrapperBridge.h @@ -0,0 +1,32 @@ +// +// Header.h +// Encapp +// +// Created by Lars Johan Blome on 10/9/25. +// + +#ifndef X264WrapperBridge_h +#define X264WrapperBridge_h +#include +#ifdef X264 +#include "x264.h" + + +// X264WrapperBridge.h +void x264_swift_log_callback(void *p_unused, int i_level, const char *psz, va_list arg); +// Helper function to set the log callback +void x264_set_log_callback(x264_param_t *params); + +// +x264_t *x264_encoder_open( x264_param_t * ); +//x264_t *x264_encoder_open_157(x264_param_t *); +void x264_encoder_close( x264_t * ); +int x264_param_default_preset( x264_param_t *, const char *preset, const char *tune ); +int x264_encoder_encode( x264_t *, x264_nal_t **pp_nal, int *pi_nal, x264_picture_t *pic_in, x264_picture_t *pic_out ); +int x264_encoder_headers( x264_t *, x264_nal_t **pp_nal, int *pi_nal ); +void x264_encoder_intra_refresh( x264_t * ); +int x264_encoder_invalidate_reference( x264_t *, int64_t pts ); +int x264_encoder_delayed_frames( x264_t * ); +int x264_encoder_maximum_delayed_frames( x264_t * ); +#endif +#endif /* X264WrapperBridge_h */