Post

Replies

Boosts

Views

Activity

AVAssetExportPresetHEVCHighestQualityWithAlpha decreases quality a lot when exporting video
Problem I need to import a video, process and then export the video with alpha. I noticed the video gets a lot grayer/loses quality compared to the original. I don't need any compression. Sidenote: I need to export video's with transparency enabled, that's why I use AVAssetExportPresetHEVCHighestQualityWithAlpha. It seems that that is causing the problem, since AVAssetExportPresetHighestQuality is looking good. This are side-by-side frames of the original and a video that's processed. The left is the original frame, the right is a processed video: https://i.stack.imgur.com/ORqfz.png This is another example where the bottom is exported and the above is the original. You can see at the bar where the YouTube NL is displayed, that the above one is almost fully black, while the below one (exported) is really gray: https://i.stack.imgur.com/s8lCn.png As far as I know, I don't do anything special, I just load the video and directly export it. It still loses quality. How can I prevent this? Reproduction path You can either clone the repository, or see the code below. The repository is available here: https://github.com/Jasperav/VideoCompression/tree/main/VideoCompressionTests. After you cloned it, run the only unit-test and check the logging of where the output of the video is stored. You can then observe that temp.mov is a lot grayer than the original video. The code of importing and exporting the video is here. As far as I can see, I just import and directly export the movie without modifying it. What's the problem? import AppKit import AVFoundation import Foundation import Photos import QuartzCore import OSLog let logger = Logger() class VideoEditor { func export( url: URL, outputDir: URL ) async { let asset = AVURLAsset(url: url) let extract = try! await extractData(videoAsset: asset) try! await exportVideo(outputPath: outputDir, asset: asset, videoComposition: extract) } private func exportVideo(outputPath: URL, asset: AVAsset, videoComposition: AVMutableVideoComposition) async throws { let fileExists = FileManager.default.fileExists(atPath: outputPath.path()) logger.debug("Output dir: \(outputPath), exists: \(fileExists), render size: \(String(describing: videoComposition.renderSize))") if fileExists { do { try FileManager.default.removeItem(atPath: outputPath.path()) } catch { logger.error("remove file failed") } } let dir = outputPath.deletingLastPathComponent().path() logger.debug("Will try to create dir: \(dir)") try? FileManager.default.createDirectory(atPath: dir, withIntermediateDirectories: true) var isDirectory = ObjCBool(false) guard FileManager.default.fileExists(atPath: dir, isDirectory: &isDirectory), isDirectory.boolValue else { logger.error("Could not create dir, or dir is a file") fatalError() } guard let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHEVCHighestQualityWithAlpha) else { logger.error("generate export failed") fatalError() } exporter.outputURL = outputPath exporter.outputFileType = .mov exporter.shouldOptimizeForNetworkUse = false exporter.videoComposition = videoComposition await exporter.export() logger.debug("Status: \(String(describing: exporter.status)), error: \(exporter.error)") if exporter.status != .completed { fatalError() } } private func extractData(videoAsset: AVURLAsset) async throws -> AVMutableVideoComposition { guard let videoTrack = try await videoAsset.loadTracks(withMediaType: .video).first else { fatalError() } let composition = AVMutableComposition(urlAssetInitializationOptions: nil) guard let compositionVideoTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: videoTrack.trackID) else { fatalError() } let duration = try await videoAsset.load(.duration) try compositionVideoTrack.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: duration), of: videoTrack, at: CMTime.zero) let naturalSize = try await videoTrack.load(.naturalSize) let preferredTransform = try await videoTrack.load(.preferredTransform) let mainInstruction = AVMutableVideoCompositionInstruction() mainInstruction.timeRange = CMTimeRange(start: CMTime.zero, end: duration) let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack) let videoComposition = AVMutableVideoComposition() let frameRate = try await videoTrack.load(.nominalFrameRate) videoComposition.frameDuration = CMTimeMake(value: 1, timescale: Int32(frameRate)) mainInstruction.layerInstructions = [layerInstruction] videoComposition.instructions = [mainInstruction] videoComposition.renderSize = naturalSize return videoComposition } }
0
0
700
Mar ’24
Github CI UITest gives flaky tests 'Unable to monitor event loop'
I am running my UI Tests on Github CI and the tests are flaky. I don't understand how I can fix it. The animations are disabled and I am running the tests on a iPhone 13 plus. A lot of tests are running green, but some are not working. Locally, I got everything working. These are some logs: 2022-06-21T13:42:23.2627250Z t = 63.34s Tap Cell 2022-06-21T13:42:23.2707530Z t = 63.34s Wait for com.project.project to idle 2022-06-21T13:42:23.2733620Z t = 63.41s Unable to monitor event loop 2022-06-21T13:42:23.2734250Z t = 63.41s Unable to monitor animations 2022-06-21T13:42:23.2734800Z t = 63.42s Find the Cell 2022-06-21T13:42:24.1158670Z t = 64.45s Find the Cell (retry 1) 2022-06-21T13:42:24.1287900Z t = 64.45s Collecting extra data to assist test failure triage 2022-06-21T13:42:24.2022460Z /Users/runner/work/project/UITestCase.swift:665: error: -[project.UserTagTest testTapInTextView] : Failed to get matching snapshot: Lost connection to the application (pid 12676). (Underlying Error: Couldn’t communicate with a helper application. Try your operation again. If that fails, quit and relaunch the application and try again. The connection to service created from an endpoint was invalidated: failed to check-in, peer may have been unloaded: mach_error=10000003.) It can not find the cell because of these logs: Unable to monitor event loop Unable to monitor animations I know this because I sometimes get different errors than the error above, which says that the connection to the application is lost, right below the Unable to monitor... error logging. Is there anything I can try? I don't have a reproduction project. This is the command that is executed: xcodebuild test -project project.xcodeproj -scheme project-iosUITests -destination 'platform=iOS Simulator,name=iPhone 13 Pro,OS=15.5' The CI runs 35 tests and 5 fails randomly with the Unable to errors. Is there any suggestion to fix this problem?
0
0
1k
Jun ’22
SwiftUI: List inside TabView inside NavigationView breaks animation
I want to have a TabView inside a NavigationView. The reason is that I am showing a List inside the TabView. When a user taps on an item in the list, the list uses a NavigationLink to show a detailed screen. The problem is that the navigationBarTitle is now broken. It does not animate when the user scrolls through the items (sometimes). I don't want to wrap my NavigationView inside the TabView, since that will always show the TabView. I don't want it. This is the reproduction code. If you run this in the simulator, the animation will break when switch a few times between the tabs and you scroll through the list. You will see that the navigation bar will remain where it is, without the animation. import SwiftUI struct ContentView: View { var body: some View { NavigationView { TabView { TestView() .tabItem { Image(systemName: "person.3") } TestView() .tabItem { Image(systemName: "person.2") } } .navigationTitle("Test") .navigationViewStyle(.stack) } } } struct TestView: View { var body: some View { List { Text("test") } .listStyle(.plain) } }
2
1
3k
Feb ’22