AVFoundation

RSS for tag

Work with audiovisual assets, control device cameras, process audio, and configure system audio interactions using AVFoundation.

AVFoundation Documentation

Posts under AVFoundation tag

362 Posts
Sort by:
Post not yet marked as solved
4 Replies
2k Views
So, I've never faced a problem like this for so long. I have basically scrutinized every possible website on the internet looking for a solution but have found nothing so far.I have a custom picker controller in which I can select videos and play them. Beforehand, I was struggling to play slow motion videos (only no-slow-motion videos were playing) but after searching I found the solution here.http://stackoverflow.com/questions/26152396/how-to-access-nsdata-nsurl-of-slow-motion-videos-using-photokitSo, my code to get videos became this:let videoOptions = PHVideoRequestOptions() videoOptions.version = PHVideoRequestOptionsVersion.Original PHImageManager.defaultManager().requestAVAssetForVideo(asset!, options: videoOptions , resultHandler: { (asset, audioMix, info) -> Void in if let asset = asset as? AVURLAsset { let videoData = NSData(contentsOfURL: asset.URL) let videoPath = NSTemporaryDirectory() + "tmpMovie.MOV" let videoURL = NSURL(fileURLWithPath: videoPath) let writeResult = videoData?.writeToURL(videoURL, atomically: true) if let writeResult = writeResult where writeResult { print("success") let videoVC = VideoViewController(videoUrl: videoURL) imagePicker.presentViewController(videoVC, animated: false, completion: nil) } else { print("failure") } } }) Now, slow motion videos are playing but in a normal way instead of in a slow-motion way. This questions relates to the problem.https://devforums.apple.com/message/903937#903937I've seen a lot of comments saying they solved the problem by using Photos framework, but I have no idea how to achieve this and they didn't explain either. It might be something to do PHAssetMediaSubtypeVideoHighFrameRate. So, how would be possible to play slow motion videos? Do I need to change the fps somehow?Please help, I am quite desperate :/ Objective-C code is welcome as well.
Posted
by
Post marked as solved
8 Replies
4.0k Views
I'm trying to do some realtime audio processing on audio served from an HLS stream (i.e. an AVPlayer created using an M3U HTTP URL). It doesn't seem like attaching an AVAudioMix configured with with an `audioTapProcessor` has any effect; none of the callbacks except `init` are being invoked. Is this a known limitation? If so, is this documented somewhere?If the above is a limitation, what are my options using some of the other audio APIs? I looked into `AVAudioEngine` as well but it doesn't seem like there's any way I can configure any of the input node types to use an HLS stream. Am I wrong? Are there lower level APIs available to play HLS streams that provide the necessary hooks?Alternatively, is there some generic way to tap into all audio being output by my app regardless of its source?Thanks a lot!
Posted
by
Post not yet marked as solved
1 Replies
615 Views
HiIs it possible to scan multiple 1D barcodes using the Apple APIs provided? I can only seem to scan multiple QR codes but when I try 1 D barcodes I only ever get one result, the code is as follows- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection { CGRect highlightViewRect = CGRectZero; AVMetadataMachineReadableCodeObject *barCodeObject; NSString *detectionString = nil; NSArray *barCodeTypes = @[AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode]; for (AVMetadataObject *metadata in metadataObjects) { for (NSString *type in barCodeTypes) { if ([metadata.type isEqualToString:type]) { barCodeObject = (AVMetadataMachineReadableCodeObject *)[_prevLayer transformedMetadataObjectForMetadataObject:(AVMetadataMachineReadableCodeObject *)metadata]; highlightViewRect = barCodeObject.bounds; detectionString = [(AVMetadataMachineReadableCodeObject *)metadata stringValue]; break; } } if (detectionString != nil) { _label.text = detectionString; break; } else _label.text = @"(none)"; } _highlightView.frame = highlightViewRect; }
Posted
by
Post not yet marked as solved
1 Replies
610 Views
I am currently working with AVAssetWriterInput with interlaced source.I want to know the proper procedure to preserve 'fiel' format description extension through AVAssetWriterInput compression operation.Do you anyone have an answer on this?>>Technical Note TN2162>>Uncompressed Y´CbCr Video in QuickTime Files>>The 'fiel' ImageDescription Extension: Field/Frame Information//What I have tried is following:First decode into sample buffer with Field/Frame information- Decode DV-NTSC source and get current FieldCount/Detail of source data- Create a kCVPixelFormatType_422YpCbCr8 CVImageBuffer from source- CMSetAttachments() kCVImageBufferFieldCountKey/kCVImageBufferFieldDetailKey with FieldCount=2/FieldDetail=14 to imageBuffer, same as DV-NTSC source- CMVideoFormatDescriptionCreateForImageBuffer()- CMSampleBufferCreateForImageBuffer()- Now decompressed samplebuffer has kCMFormatDescriptionExtension_FieldXXX same as sourceSecond encode using ProRes422- Next I create AVAssetWriterInput to transcode from _422YpCbCr8 into AVVideoCodecAppleProRes422- Now AVAssetWriter can produce ProRes422 mov file, but it does not contain the format description extension 'fiel'.- ProRes422 Encoder does preserve 'colr', 'pasp', 'clap' same as source, but no 'fiel' is there.I have also tried to serve format description with kCMFormatDescriptionExtension_FieldXXX with initWithMediaType:outputSettings:sourceFormatHint:but no success.//
Posted
by
Post not yet marked as solved
2 Replies
1.8k Views
Currently, I'm recording audio on the Apple Watch using the presentAudioRecorderController and sending it to the corresponding iPhone app.The audio format by default seems to be recorded on the Apple Watch using two channels and there doesn't seem to be a way to change that.For various reasons, I need the audio format to be only one channel. I was hoping there would be something on iOS to convert the audio file from stereo (two channels) to mono (one channel)Right now, I'm investigating if this is possible using AVAudioEngine and other various related classes. I'm not sure if it's possible and it seems very complicated at the moment.
Posted
by
Post not yet marked as solved
9 Replies
3.5k Views
Hi,I'm having two problems using the scheduleBuffer function of AVAudioPlayerNode.Background: my app generates audio programatically, which is why I am using this function. I also need low latency. Therefore, I'm using a strategy of scheduling a small number of buffers, and using the completion handler to keep the process moving forward by scheduling one more buffer for each one that completes.I'm seeing two problems with this approach:One, the total memory consumed by my app grows steadily while the audio is playing, which suggests that the audio buffers are never being deallocated or some other runaway process is underway. (The Leaks tool doesn't detect any leaks, however).Two, audio playback sometimes stops, particularly on slower devices. By "stops", what I mean is that at some point I schedule a buffer and the completion block for that buffer is never called. When this happens, I can't even clear the problem by stopping the player.Now, regarding the first issue, I suspected that if my completion block recursively scheduled another buffer with another completion block, I would probably end up blowing out the stack with an infinite recursion. To get around this, instead of directly scheduling the buffer in the completion block, I set it up to enqueue the schedule in a dispatch queue. However, this doesn't seem to solve the problem.Any advice would be appreciated. Thanks.
Posted
by
Post not yet marked as solved
2 Replies
1.8k Views
I am working on AVPlayer based streaming apps wherein I am relying on ID3 tags for fetching metadata from the HLS stream. I am using KVO for this and observing AVPlayerItem’s timedMetadata property. This works perfectly well in normal scenario. However when I route the playback to Apple TV via Airplay, I do not get any notifications for the said KVO. In fact, the timedMetadata property resets to nil once the Airplay is activated as the API docs says here,“As an optimization for playback, AVPlayerItem may omit the processing of timed metadata when no observer of this property is registered. Therefore, when no such observer is registered, the value of the timedMetadata property may remain nil regardless of the contents of the underlying media.”Is there any way, we can fetch timedMetadata property of AVPlayerItem while the steam is being played via Airplay mode.
Posted
by
Post marked as solved
3 Replies
1.9k Views
In this URL there is the following blerb:https://www.apple.com/in/ipados/ipados-preview/features/Image Capture APIThe Image Capture API allows developers to leverage the Camera Connection Kit to import photos directly into their apps.I haven't been able to find in the docs or WWDC sessions where it talks about this. I have an app for our action camera and would love to be able to directly read the camera's filesystem over USB. I see where you can use a a document picker to access a USB filesystem, but that requires the user to properly find/select the correct directory in the camera's file system. I am hoping to be able to detect it and access it without the error prone user selection.
Posted
by
Post not yet marked as solved
4 Replies
2.2k Views
I'm using AVAssetReaders with AVSampleBufferDisplayLayers to display multiple videos at once. I'm seeing this issue on iOS 13.1.3, 13.2b2, on various hardware like iPad 10.5 and iPad 12.9.It works well for a while, then a random call to copyNextSampleBuffer never returns, blocking that thread indefinitely and eating up resources.I have tried different threading approaches with no avail:If copyNextSampleBuffer() and reader.cancelReading() are done on the same queue, then copyNextSampleBuffer() gets stuck and the cancelReading() never gets processed because the queue is blocked. If I manually (with the debugger) jump in on that blocked queue and execute cancelReading(), immediately an EXC_BREAKPOINT crashes the appIf copyNextSampleBuffer() and reader.cancelReading() are done on different queues, then copyNextSampleBuffer() crashes with EXC_BAD_ACCESSHere's the stacktrace (same queue approach). I don't understand why it's stuck, my expectation is that copyNextSampleBuffer should always return (ie. with nil in error case).VideoPlayerView: UIView with AVSampleBufferDisplayLayerAVAssetFactory: Singleton with the queue that creates & manages all AVAssetReader / AVAsset* objects* thread #22, queue = 'AVAssetFactory' frame #0: 0x00000001852355f4 libsystem_kernel.dylib`mach_msg_trap + 8 frame #1: 0x0000000185234a60 libsystem_kernel.dylib`mach_msg + 72 frame #2: 0x00000001853dc068 CoreFoundation`__CFRunLoopServiceMachPort + 216 frame #3: 0x00000001853d7188 CoreFoundation`__CFRunLoopRun + 1444 frame #4: 0x00000001853d68bc CoreFoundation`CFRunLoopRunSpecific + 464 frame #5: 0x000000018f42b6ac AVFoundation`-[AVRunLoopCondition _waitInMode:untilDate:] + 400 frame #6: 0x000000018f38f1dc AVFoundation`-[AVAssetReaderOutput copyNextSampleBuffer] + 148 frame #7: 0x000000018f3900f0 AVFoundation`-[AVAssetReaderTrackOutput copyNextSampleBuffer] + 72 * frame #8: 0x0000000103309d98 Photobooth`closure #1 in AVAssetFactory.nextSampleBuffer(reader=0x00000002814016f0, retval=(Swift.Optional<CoreMedia.CMSampleBuffer>, Swift.Optional<AVFoundation.AVAssetReader.Status>) @ 0x000000016dbd1cb8) at AVAssetFactory.swift:108:34 frame #9: 0x0000000102f4f480 Photobooth`thunk for @callee_guaranteed () -> () at <compiler-generated>:0 frame #10: 0x0000000102f4f4a4 Photobooth`thunk for @escaping @callee_guaranteed () -> () at <compiler-generated>:0 frame #11: 0x000000010bfe6c04 libdispatch.dylib`_dispatch_client_callout + 16 frame #12: 0x000000010bff5888 libdispatch.dylib`_dispatch_lane_barrier_sync_invoke_and_complete + 124 frame #13: 0x0000000103309a5c Photobooth`AVAssetFactory.nextSampleBuffer(reader=0x00000002814016f0, self=0x0000000281984f60) at AVAssetFactory.swift:101:20 frame #14: 0x00000001032ab690 Photobooth`closure #1 in VideoPlayerView.setRequestMediaLoop(self=0x000000014b8da1d0, handledCompletion=false) at VideoPlayerView.swift:254:70 frame #15: 0x0000000102dce978 Photobooth`thunk for @escaping @callee_guaranteed () -> () at <compiler-generated>:0 frame #16: 0x000000018f416848 AVFoundation`-[AVMediaDataRequester _requestMediaDataIfReady] + 80 frame #17: 0x000000010bfe5828 libdispatch.dylib`_dispatch_call_block_and_release + 24 frame #18: 0x000000010bfe6c04 libdispatch.dylib`_dispatch_client_callout + 16 frame #19: 0x000000010bfedb74 libdispatch.dylib`_dispatch_lane_serial_drain + 744 frame #20: 0x000000010bfee744 libdispatch.dylib`_dispatch_lane_invoke + 500 frame #21: 0x000000010bff9ae4 libdispatch.dylib`_dispatch_workloop_worker_thread + 1324 frame #22: 0x000000018517bfa4 libsystem_pthread.dylib`_pthread_wqthread + 276I've tried all kinds of other things like making sure the AVAssets and all objects are made on one queue, and stopping the AVAssetReaders from ever deallocing to see if that helps. Nothing works. Any ideas?
Posted
by
Post not yet marked as solved
4 Replies
1.2k Views
I'm having an issue with playing sequences of different kinds of items in a background.In an app I'm working on we've introduced playlists which contain both content provided by the app and Apple Music content.For that use AVPlayer and MPMusicPlayerController respectively. We observe one player or the other (depending what content is now playing) and if the other kind of content comes next, we release the old player (if we can - MPMusicPlayerController is a singleton, so best we can do is stop it) and load item to another player.The problem starts when the app leaves foreground. Once MPMusicPlayerController takes over it doesn't want to give up control, so if any AVPlayer content comes after MPMusicPlayerController content, the music stops.One workaround that I've tried is playing with `.mixWithOthers` options when I set the category on AVAudioSession, however this creates new category of problems - I'm loosing lockscreen controls, therefore I'm also loosing airplay. One dirty trick that I've tried was setting `.mixWithOthers` 3 seconds before MPMediaItem ends, and then disabling it back once AVPlayer starts. Beside the fact that there're probably many different things that can go wrong here, MPMediaPlayerController still doesn't want to give me back the control over lockscreen controls.Is there any way this could ever work on iOS 13?
Posted
by
Post not yet marked as solved
11 Replies
4.3k Views
I am putting together a simple video editor app for iOS. The videos are exported with a "watermark" in the form of a text overlay (e.g. "This video was made with XYZ").The app (still a prototype) was working until around February this year. Then I got busy, moved to other projects and stopped working on it for a while.About a months ago, I resumed work on the app but suddenly noticed that it was crashing whenever I attempted to export any video.The crash looks like this:libxpc.dylib`_xpc_api_misuse: 0x7fff51c53154 <+0>: pushq %rbp 0x7fff51c53155 <+1>: movq %rsp, %rbp 0x7fff51c53158 <+4>: pushq %rbx 0x7fff51c53159 <+5>: subq $0xa8, %rsp 0x7fff51c53160 <+12>: movq %rdi, %r9 0x7fff51c53163 <+15>: movaps 0xdba6(%rip), %xmm0 ; __xpcVersionNumber + 160 0x7fff51c5316a <+22>: leaq -0xb0(%rbp), %rbx 0x7fff51c53171 <+29>: movaps %xmm0, 0x90(%rbx) 0x7fff51c53178 <+36>: movaps %xmm0, 0x80(%rbx) 0x7fff51c5317f <+43>: movaps %xmm0, 0x70(%rbx) 0x7fff51c53183 <+47>: movaps %xmm0, 0x60(%rbx) 0x7fff51c53187 <+51>: movaps %xmm0, 0x50(%rbx) 0x7fff51c5318b <+55>: movaps %xmm0, 0x40(%rbx) 0x7fff51c5318f <+59>: movaps %xmm0, 0x30(%rbx) 0x7fff51c53193 <+63>: movaps %xmm0, 0x20(%rbx) 0x7fff51c53197 <+67>: movaps %xmm0, 0x10(%rbx) 0x7fff51c5319b <+71>: movaps %xmm0, (%rbx) 0x7fff51c5319e <+74>: leaq 0x1150d(%rip), %r8 ; "XPC API Misuse: %s" 0x7fff51c531a5 <+81>: movl $0xa0, %esi 0x7fff51c531aa <+86>: movl $0xa0, %ecx 0x7fff51c531af <+91>: movq %rbx, %rdi 0x7fff51c531b2 <+94>: movl $0x0, %edx 0x7fff51c531b7 <+99>: xorl %eax, %eax 0x7fff51c531b9 <+101>: callq 0x7fff51c5fe18 ; symbol stub for: __snprintf_chk 0x7fff51c531be <+106>: movq %rbx, 0x380787c3(%rip) ; gCRAnnotations + 8 0x7fff51c531c5 <+113>: leaq 0x114f9(%rip), %rax ; "API Misuse" 0x7fff51c531cc <+120>: movq %rax, 0x380787bd(%rip) ; gCRAnnotations + 16 -> 0x7fff51c531d3 <+127>: ud2 < Thread 55: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)After experimenting a bit by eliminating features, I found out that the app crashes only if the exported video compositions contain the text overlay: if I comment out the code responsible for overlaying the text layer, the issue resolves.This is the code I am using to export the video composition:func export(completion: @escaping (() -> Void), failure: @escaping ((Error) -> Void)) { let exportQuality = AVAssetExportPresetHighestQuality guard let exporter = AVAssetExportSession(asset: composition, presetName: exportQuality) else { return failure(ProjectError.failedToCreateExportSession) } guard let documents = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) else { return failure(ProjectError.temporaryOutputDirectoryNotFound) } let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd_HHmmss" let fileName = dateFormatter.string(from: Date()) let fileExtension = "mov" let fileURL = documents.appendingPathComponent(fileName).appendingPathExtension(fileExtension) exporter.outputURL = fileURL exporter.outputFileType = AVFileType.mov exporter.shouldOptimizeForNetworkUse = true if shouldAddWatermark { // Watermark overlay: let frame = CGRect(origin: .zero, size: videoComposition.renderSize) let watermark = WatermarkLayer(frame: frame) let parentLayer = CALayer() let videoLayer = CALayer() parentLayer.frame = frame videoLayer.frame = frame parentLayer.addSublayer(videoLayer) parentLayer.addSublayer(watermark) videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer) } exporter.videoComposition = videoComposition exporter.exportAsynchronously { if exporter.status == .completed { /* Composition was successfully saved to the documents folder. Now create a new asset in the device's camera roll (i.e. photo library): */ AssetLibrary.saveVideo(at: fileURL, completion: { completion() }, failure: {(error) in failure(ProjectError.failedToExportToPhotoLibrary(detail: error?.localizedDescription ?? "Unknown")) }) } else { DispatchQueue.main.async { failure(ProjectError.failedToExportComposition(detail: exporter.error?.localizedDescription ?? "Unknown")) } } } }The WatermarkLayer class used above is defined as follows:class WatermarkLayer: CATextLayer { // MARK: - Constants private let defaultFontSize: CGFloat = 48 private let rightMargin: CGFloat = 10 private let bottomMargin: CGFloat = 10 // MARK: - Initialization init(frame: CGRect) { super.init() guard let appName = Bundle.main.infoDictionary?["CFBundleName"] as? String else { fatalError("!!!") } self.foregroundColor = CGColor.srgb(r: 255, g: 255, b: 255, a: 0.5) self.backgroundColor = CGColor.clear self.string = String(format: String.watermarkFormat, appName) self.font = CTFontCreateWithName(String.watermarkFontName as CFString, defaultFontSize, nil) self.fontSize = defaultFontSize self.shadowOpacity = 0.75 self.alignmentMode = .right self.frame = frame } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented. Use init(frame:) instead.") } // MARK: - CALayer override func draw(in ctx: CGContext) { let height = self.bounds.size.height let fontSize = self.fontSize //let yDiff = (height-fontSize)/2 - fontSize/10 // Center let yDiff = (height-fontSize) - fontSize/10 - bottomMargin // Bottom (minus margin) ctx.saveGState() ctx.translateBy(x: -rightMargin, y: yDiff) super.draw(in: ctx) ctx.restoreGState() } }What's going on? Which API is being "misused"?
Posted
by
Post not yet marked as solved
2 Replies
1.9k Views
I'm trying to make an app that plays audio when push is received, even while the ringer is silent.I have the audio background mode enabled and the app works (usually) fine, but sometimes i get a mysterious 561015905 error.The error isAVAudioSession.ErrorCode.cannotStartPlayingAnd docs indicate:This error type can occur if the app’s Information property list doesn’t permit audio use. It can also occur if the app is in the background and using a category that doesn’t allow background audio.https://developer.apple.com/documentation/avfoundation/avaudiosession/errorcode/cannotstartplayingHowever, the audio mode is definitely enabled and the category is always playback that should allow background playing.(this works 95-99% of times)So, with intesnse testing i have found that once every 20-100 incoming pushes i get this error:Error: Error Domain=NSOSStatusErrorDomain Code=561015905 "(null)"Why?
Posted
by
Post not yet marked as solved
3 Replies
1.8k Views
I am using the microphone, and found a lot of issues that crashes the app when the input source did change. The error was always something like: ** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: format.sampleRate == hwFormat.sampleRate. Now I have fixed this issue, forcing the input-source to be always the builtin microphone and using AVAudioFoundation entities at different moments. But I am still not confident about this solution. For example, I still having some inconsistencies while transmitting the device screen on macOS through QuickTime. So my question around this: How to prevent app-crashes with this kind of error? I saw a lot of similar errors just changing the property of the format. How can I avoid these kinds of errors? There is a Swift-way to handle the error instead of using an exception catcher from Objective-c?
Posted
by
Post not yet marked as solved
10 Replies
6.1k Views
Hi, I'm working on an app where a user can scroll through a feed of short videos (a bit like TikTok). I do some pre-fetching of videos a couple positions ahead of the user's scroll position, so the video can start playing as soon as he or she scrolls to the video. Currently, I just pre-fetch by initializing a few AVPlayers. However, I'd like to add a better caching system. I'm looking for the best way to: get videos to start playing as possible, while making sure to minimize re-downloading of videos if a user scrolls away from a video and back to it. Is there a way that I can cache the contents of an AVPlayer that has loaded an HLS video? Alternatively, I've explored using AVAssetDownloadTask to download the HLS videos. My issue is that I can't download the full video and then play it - I need to start playing the video as soon as the user scrolls to it, even if it's not done downloading. Is there a way to start an HLS download with an AVAssetDownloadTask, and then start playing the video while it continues downloading? Thank you!
Posted
by
Post not yet marked as solved
1 Replies
1.5k Views
We are creating a watch party app that allows you to video chat with your friends and play a YouTube video at the same time. The video is played using Google's youtube-ios-player-helperlibrary which uses a WKWebView with their iframe API, as that's the only way to play it without violating the Terms of Service. We need the ability to change the volume of the YouTube video separately from the video chat, so you can hear your friends over the video for example. Unfortunately it's not possible to directly change the volume because iOS does not support changing the volume via JavaScript - https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html#//apple_ref/doc/uid/TP40009523-CH5-SW10, unlike macOS. Setting volume doesn't do anything and getting it always returns 1. Users can change the volume with the hardware buttons but this applies to all audio including the video chat, not just the YouTube video. Someone found a workaround - https://stackoverflow.com/a/37315071/1795356 to get the underlying AVPlayer and change its volume natively. This worked with UIWebView but does not work now that it uses WKWebView. What can be done to change the volume of the YouTube video?
Posted
by
Post not yet marked as solved
3 Replies
1.6k Views
Summary: I am using the Vision framework, in conjunction with AVFoundation, to detect facial landmarks of each face in the camera feed (by way of the VNDetectFaceLandmarksRequest). From here, I am taking the found observations and unprojecting each point to a SceneKit View (SCNView), then using those points as the vertices to draw a custom geometry that is textured with a material over each found face. Effectively, I am working to recreate how an ARFaceTrackingConfiguration functions. In general, this task is functioning as expected, but only when my device is using the front camera in landscape right orientation. When I rotate my device, or switch to the rear camera, the unprojected points do not properly align with the found face as they do in landscape right/front camera. Problem: When testing this code, the mesh appears properly (that is, appears affixed to a user's face), but again, only when using the front camera in landscape right. While the code runs as expected (that is, generating the face mesh for each found face) in all orientations, the mesh is wildly misaligned in all other cases. My belief is this issue either stems from my converting the face's bounding box (using VNImageRectForNormalizedRect, which I am calculating using the width/height of my SCNView, not my pixel buffer, which is typically much larger), though all modifications I have tried result in the same issue. Outside of that, I also believe this could be an issue with my SCNCamera, as I am a bit unsure how the transform/projection matrix works and whether that would be needed here. Sample of Vision Request Setup: // Setup Vision request options var requestHandlerOptions: [VNImageOption: AnyObject] = [:] // Setup Camera Intrinsics let cameraIntrinsicData = CMGetAttachment(sampleBuffer, key: kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix, attachmentModeOut: nil) if cameraIntrinsicData != nil { requestHandlerOptions[VNImageOption.cameraIntrinsics] = cameraIntrinsicData } // Set EXIF orientation let exifOrientation = self.exifOrientationForCurrentDeviceOrientation() // Setup vision request handler let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: exifOrientation, options: requestHandlerOptions) // Setup the completion handler let completion: VNRequestCompletionHandler = {request, error in let observations = request.results as! [VNFaceObservation] // Draw faces DispatchQueue.main.async { drawFaceGeometry(observations: observations) } } // Setup the image request let request = VNDetectFaceLandmarksRequest(completionHandler: completion) // Handle the request do { try handler.perform([request]) } catch { print(error) } Sample of SCNView Setup: // Setup SCNView let scnView = SCNView() scnView.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(scnView) scnView.showsStatistics = true NSLayoutConstraint.activate([ scnView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), scnView.topAnchor.constraint(equalTo: self.view.topAnchor), scnView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor), scnView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor) ]) // Setup scene let scene = SCNScene() scnView.scene = scene // Setup camera let cameraNode = SCNNode() let camera = SCNCamera() cameraNode.camera = camera scnView.scene?.rootNode.addChildNode(cameraNode) cameraNode.position = SCNVector3(x: 0, y: 0, z: 16) // Setup light let ambientLightNode = SCNNode() ambientLightNode.light = SCNLight() ambientLightNode.light?.type = SCNLight.LightType.ambient ambientLightNode.light?.color = UIColor.darkGray scnView.scene?.rootNode.addChildNode(ambientLightNode) Sample of "face processing" func drawFaceGeometry(observations: [VNFaceObservation]) { // An array of face nodes, one SCNNode for each detected face var faceNode = [SCNNode]() // The origin point let projectedOrigin = sceneView.projectPoint(SCNVector3Zero) // Iterate through each found face for observation in observations { // Setup a SCNNode for the face let face = SCNNode() // Setup the found bounds let faceBounds = VNImageRectForNormalizedRect(observation.boundingBox, Int(self.scnView.bounds.width), Int(self.scnView.bounds.height)) // Verify we have landmarks if let landmarks = observation.landmarks { // Landmarks are relative to and normalized within face bounds let affineTransform = CGAffineTransform(translationX: faceBounds.origin.x, y: faceBounds.origin.y) .scaledBy(x: faceBounds.size.width, y: faceBounds.size.height) // Add all points as vertices var vertices = [SCNVector3]() // Verify we have points if let allPoints = landmarks.allPoints { // Iterate through each point for (index, point) in allPoints.normalizedPoints.enumerated() { // Apply the transform to convert each point to the face's bounding box range _ = index let normalizedPoint = point.applying(affineTransform) let projected = SCNVector3(normalizedPoint.x, normalizedPoint.y, CGFloat(projectedOrigin.z)) let unprojected = sceneView.unprojectPoint(projected) vertices.append(unprojected) } } // Setup Indices var indices = [UInt16]() // Add indices // ... Removed for brevity ... // Setup texture coordinates var coordinates = [CGPoint]() // Add texture coordinates // ... Removed for brevity ... // Setup texture image let imageWidth = 2048.0 let normalizedCoordinates = coordinates.map { coord -> CGPoint in let x = coord.x / CGFloat(imageWidth) let y = coord.y / CGFloat(imageWidth) let textureCoord = CGPoint(x: x, y: y) return textureCoord } // Setup sources let sources = SCNGeometrySource(vertices: vertices) let textureCoordinates = SCNGeometrySource(textureCoordinates: normalizedCoordinates) // Setup elements let elements = SCNGeometryElement(indices: indices, primitiveType: .triangles) // Setup Geometry let geometry = SCNGeometry(sources: [sources, textureCoordinates], elements: [elements]) geometry.firstMaterial?.diffuse.contents = textureImage // Setup node let customFace = SCNNode(geometry: geometry) sceneView.scene?.rootNode.addChildNode(customFace) // Append the face to the face nodes array faceNode.append(face) } // Iterate the face nodes and append to the scene for node in faceNode { sceneView.scene?.rootNode.addChildNode(node) } }
Posted
by
Post not yet marked as solved
4 Replies
1.4k Views
Hello, I am using HLS audio stream and I get metadata to show the song info, artist info etc., in the app using AVPlayer. In iOS 14, I see the artwork data (which embeds in WXXX frame of id3 tag) is coming over across along with other metadata. The same stream is working fine and showing artwork data in iOS 13. Does anything changed in iOS 14 which effects this metadata? Please let me know Thank you
Posted
by
Post marked as solved
5 Replies
1.9k Views
I am currently working on a macOS app which will be creating very large video files with up to an hour of content. However, generating the images and adding them to AVAssetWriter leads to VTDecoderXPCService using 16+ GB of memory and the kernel-task using 40+ GB (the max I saw was 105GB). It seems like the generated video is not streamed onto the disk but rather written to memory for it to be written to disk all at once. How can I force it to stream the data to disk while the encoding is happening? Btw. my app itself consistently needs around 300MB of memory, so I don't think I have a memory leak here. Here is the relevant code: func analyse() { 				self.videoWritter = try! AVAssetWriter(outputURL: outputVideo, fileType: AVFileType.mp4) 				let writeSettings: [String: Any] = [ 						AVVideoCodecKey: AVVideoCodecType.h264, 						AVVideoWidthKey: videoSize.width, 						AVVideoHeightKey: videoSize.height, 						AVVideoCompressionPropertiesKey: [ 								AVVideoAverageBitRateKey: 10_000_000, 						] 				] 				self.videoWritter!.movieFragmentInterval = CMTimeMake(value: 60, timescale: 1) 				self.frameInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: writeSettings) 				self.frameInput?.expectsMediaDataInRealTime = true 				self.videoWritter!.add(self.frameInput!) 				if self.videoWritter!.startWriting() == false { 						print("Could not write file: \(self.videoWritter!.error!)") 						return 				} } func writeFrame(frame: Frame) { 				/* some more code to determine the correct frame presentation time stamp */ 				let newSampleBuffer = self.setTimeStamp(frame.sampleBuffer, newTime: self.nextFrameStartTime!) 				self.frameInput!.append(newSampleBuffer) 				/* some more code */ } func setTimeStamp(_ sample: CMSampleBuffer, newTime: CMTime) -> CMSampleBuffer { 				var timing: CMSampleTimingInfo = CMSampleTimingInfo( 						duration: CMTime.zero, 						presentationTimeStamp: newTime, 						decodeTimeStamp: CMTime.zero 				) 				var newSampleBuffer: CMSampleBuffer? 				CMSampleBufferCreateCopyWithNewTiming( 						allocator: kCFAllocatorDefault, 					 sampleBuffer: sample, 					 sampleTimingEntryCount: 1, 					 sampleTimingArray: &timing, 					 sampleBufferOut: &newSampleBuffer 			 ) 				return	newSampleBuffer! 		} My specs: MacBook Pro 2018 32GB Memory macOS Big Sur 11.1
Posted
by
Post not yet marked as solved
1 Replies
1.3k Views
I implemented a custom player and used AVPictureInPictureController. pip button is coming and also calling startPictureInPicture() in action. controller.isPictureInPicturePossible is returning true. AVPictureInPictureController delegates are not receiving the call. Any help? func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {     print("PIP will start") } Have enabled Picture in picture in background mode capability set AVAudioSession category to playback in appdelegate set AVAudioSession.sharedInstance().setActive(true) as true
Posted
by
Post marked as solved
4 Replies
6k Views
Hello there, in our team we were requested to add the possibility to manually select the video quality. I know that HLS is an adaptive stream and that depending on the network condition it choose the best quality that fits to the current situation. I also tried some setting with preferredMaximumResolution and preferredPeakBitRate but none of them worked once the user was watching the steam. I also tried something like replacing the currentPlayerItem with the new configuration but anyway this only allowed me to downgrade the quality of the video. When I wanted to set it for example to 4k it did not change to that track event if I set a very high values to both params mentioned above. My question is if there is any method which would allow me to force certain quality from the manifest file. I already have some kind of extraction which can parse the manifest file and provide me all the available information but I couldn't still figure out how to make the player reproduce specific stream with my desired quality from the available playlist.
Posted
by