FFMpeg on iOS Swift - ios

I'm trying to learn FFMpeg through this tutorial: http://dranger.com/ffmpeg/tutorial01.html
I was hoping that just translating the C code to swift should get me up and running but I guess I was mistaken
I tried converting the following code:
AVFormatContext *pFormatCtx = NULL;
// Open video file
if(avformat_open_input(&pFormatCtx, argv[1], NULL, 0, NULL)!=0) {}
to:
let pFormatCtx : UnsafeMutablePointer<UnsafeMutablePointer<AVFormatContext>> = nil
// Open video file
if avformat_open_input(pFormatCtx, path, nil, opaque) != 0 {}
This code breaks at: if avformat_open_input(pFormatCtx, path, nil, opaque) != 0 {} With an EXC_BAD_ACCESS error
can anyone guess whats wrong here??
By the way I have the FFMpeg library compiling without an issue so I don't think there might be an issue with the way I compiled or imported it. I'm probably passing wrong arguments I think :/ Any guesses??

First off I'm using Swift 2 with xCode 7.2 ...
The solution was to create the format Context as an "UnsafeMutablePointer< AVFormatContext >" and then pass its address through the avformat_open_input method. Here's the code that worked for me:
var formatContext = UnsafeMutablePointer<AVFormatContext>()
if avformat_open_input(&formatContext, path, nil, nil) != 0 {
print("Couldn't open file")
return
}
Hope this helps.

The partial solution & background explanation can be found here: http://en.swifter.tips/pointer-memory/.
Basically, the UnsafeMutablePointer must be allocated before being used.
To make the code above work, try this:
let path = ...
let formatContext = UnsafeMutablePointer<UnsafeMutablePointer<AVFormatContext>>.alloc(1)
if (avformat_open_input(formatContext, path, nil, nil) != 0) {
// TODO: Error handling
}
When you are done, do not forget to call formatContext.destroy().

Related

Why is url.bookmarkData returning nil?

We have an implementation with the UIDocumentPickerViewController that looks something like this:
case .openInitialization:
// Setup UIDocumentPicker.
if #available(iOS 14, *) {
documentsPicker = UIDocumentPickerViewController(forOpeningContentTypes: [
UTType.text,
UTType.utf8PlainText,
UTType.flatRTFD,
UTType.pdf])
} else {
documentsPicker = UIDocumentPickerViewController(documentTypes: [
String(kUTTypeText),
String(kUTTypeUTF8PlainText),
String(kUTTypeFlatRTFD),
String(kUTTypePDF)], in: .open)
}
Everything works great and we can select a document. When we select a document we get a document url but in some cases (especially with one drive) we get issues when we want to turn the url into a bookmark. Following code returns nil:
guard let bookmark = try? url.bookmarkData(options: .minimalBookmark, includingResourceValuesForKeys: nil, relativeTo: nil) else { return }
Do anyone have an idea to why this is happening? Or what we can do to get it to work without returning nil?
Edit:
We've tryed to add try catch and we got following error which doesn't quite help much: Error Domain=NSCocoaErrorDomain Code=260 (file doesn't exist).
Edit 2:
So if I open from archive directly into our app it works no issues at all. But we still need to work from UIDocumentPickerViewController.
Also for some reasons files unlocked this way will just work from UIDocumentPickerViewController afterward.
Files can also be opened from onedrive and from there be opened in another app (ours). But this does't and gives a file does not exist error as well.
Edit 3:
So I've tested and read a ton. I can tell that following will return false for some files picked by documentpicker:
var exist = FileManager.default.fileExists(atPath: url.path)
But again if I open the file just once from iOS archive app it will work perfectly fine afterward. If there just were some way to tell it to update/download like apples does.
Edit 4:
I've made a sample project demonstrating the problem at github .
I answered a similar question here: PDFKit doesn’t work on iPads while works fine on a simulator [iOS, Swift]
Can you check if wrapping your url in a security access scope helps?:
url.startAccessingSecurityScopedResource()
print(FileManager.default.fileExists(atPath: url.path))
url.stopAccessingSecurityScopedResource()
The above should print true. This is because these API's access files outside of the applications sandbox.
See: https://developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories
Used a technical ticket for apple and they came with a solution :D
NSFileCoordinator().coordinate(readingItemAt: url, options: .withoutChanges, error:&err, byAccessor: { (newURL: URL) -> Void in
do {
let bookmark = try newURL.bookmarkData()
} catch let error {
print("\(error)")
}
})
if let err = err {
print(err.localizedDescription)
}

phResourceManager.writeData(for... wont run on iOS 14

Before I updated to iOS 14 on my iPhone, this code was working perfectly. After, iOS 14 this is weirdly not running... it is very odd and I have not seen any solution online, additionally from my investigation, I have not been able to see any change.
This code is used in order to retrieve a videoURL for this video from the imported Camera Roll (I use import Photos...).
phResourceManager.writeData(for: resource.last!, toFile: newURL!, options: resourceRequestOptions) { (error) in
if error != nil {
print(error, "not c67omplted error?")
} else {
print("woah completedd 345?")
newUserTakenVideo.videoURL = newURL
print(newUserTakenVideo.videoURL, "<--?")
}
}
EDIT:
To be clear, it "does not run" means the compleition block never runs... as in it never even runs and gives an error, the compleition block simply never is called (nothing prints at least..)
And here is a print statement printing out all the values I pass in to the parameters:
phResourceManager:
<PHAssetResourceManager: 0x282d352c0>
resource.last:
Optional(<PHAssetResource: 0x28128bc00> {
type: video
uti: public.mpeg-4
filename: v07044090000bu6n1nhlp4leque7r720.mp4
asset: C97B45D3-7039-4626-BA3E-BCA67912A2A9/L0/001
locallyAvailable: YES
fileURL: file:///var/mobile/Media/DCIM/113APPLE/IMG_3404.MP4
width: 576
height: 1024
fileSize: 4664955
analysisType: unavailable
cplResourceType: Original
isCurrent: YES
})
newURL:
Optional(file:///var/mobile/Containers/Data/Application/E2792F47-142E-4601-8D5B-F549D03C9AFE/Documents/Untitled%2027228354.MP4)
resourceRequestOptions:
<PHAssetResourceRequestOptions: 0x28230d480>
Note: this is the decleration for the resource variable:
let resource = PHAssetResource.assetResources(for: (cell?.assetPH)!)
I have a solution to this! Swift 4+, tested on iOS 14!
I looked through using a PHAssetResourceRequest, but the file names were messed with in the process, and it generally didn't work with my sandbox. Then I also tried requesting a AVPlayerItem from the PHAsset but this too, did not work with sandboxing...
But then, I tried simply using PHAssetResourceManager.default().writeData(... and seemingly started working!
I tested a bit more and seemed to work, here is the full code:
let resource = PHAssetResource.assetResources(for: (cell?.assetPH)!)
let resourceRequestOptions = PHAssetResourceRequestOptions()
let newURL = ExistingMediaVC.newFileUrl
PHAssetResourceManager.default().writeData(for: resource.last!, toFile: newURL!, options: resourceRequestOptions) { (error) in
if error != nil {
print(error, "error")
} else {
print("good")
newUserTakenVideo.videoURL = newURL
}
}
It is quite simple!! Tell me if anything is not working, and note I still use the ExisitingMedia.fileURL variable you used in your original code as well :)

Error trying to upload an image to CloudKit using Swift3

I'm running into a compiler error when using the following code:
func saveImageToDisk() {
let imageData = UIImagePNGRepresentation(imageView.image!)!
let fileName = getDocumentsDirectory().appendingPathComponent("image.png")
imageData.writeToFile(fileName, atomically: true)
}
The error is: Value of type 'Data' has no member 'writeToFile'
Could this be a compiler error, or something I'm missing? Thanks
SE-0005 proposed a better translation of Objective-C APIs into Swift and that affected NSData (or just Data now). Instead of writeToFile you'll have to use write(to:options:) (or even just write(to:)). Here is the documentation for the updated method.

Create a copy of CMSampleBuffer in Swift 2.0

This has been asked before, but something must have changed in Swift since it was asked. I am trying to store CMSampleBuffer objects returned from an AVCaptureSession to be processed later. After some experimentation I discovered that AVCaptureSession must be reusing its CMSampleBuffer references. When I try to keep more than 15 the session hangs. So I thought I would make copies of the sample buffers. But I can't seem to get it to work. Here is what I have written:
var allocator: Unmanaged<CFAllocator>! = CFAllocatorGetDefault()
var bufferCopy: UnsafeMutablePointer<CMSampleBuffer?>
let err = CMSampleBufferCreateCopy(allocator.takeRetainedValue(), sampleBuffer, bufferCopy)
if err == noErr {
bufferArray.append(bufferCopy.memory!)
} else {
NSLog("Failed to copy buffer. Error: \(err)")
}
This won't compile because it says that Variable 'bufferCopy' used before being initialized. I've looked at many examples and they'll either compile and not work or they won't compile.
Anyone see what I'm doing wrong here?
You can simply pass a CMSampleBuffer? variable (which, as an optional,
is implicitly initialized with nil) as inout argument with
&:
var bufferCopy : CMSampleBuffer?
let err = CMSampleBufferCreateCopy(kCFAllocatorDefault, buffer, &bufferCopy)
if err == noErr {
// ...
}
Literally you're attempting to use the variable bufferCopy before it is initialized.
You've declared a type for it, but haven't allocated the memory it's pointing to.
You should instead create CMSampleBuffers using the following call https://developer.apple.com/library/tvos/documentation/CoreMedia/Reference/CMSampleBuffer/index.html#//apple_ref/c/func/CMSampleBufferCreate
You should be able to copy the buffer into this then (as long as the format of the buffer matches the one you're copying from).

Found nil while unwrapping optional value

You might think: "another post about this error".
Yes, i've been looking into this forum before writing this question and unfortunately i couldn't find something that could help, or atleast i know that this error gets on when there is a var that is not bound.
However since im quite new into this, i'd like some help.
I'm following a guide to make a simple infinite side scroller game.
So far everything went good but then i encountered this "nill" error.
The guide itself does not have this error.
So i tought maybe it could be that i use a newer version of xCode or iphone simulation. But im pretty sure its not about that.
My codings so far:
import Foundation
class MainScene: CCNode {
weak var hero: CCSprite!
func didLoadFromCCB() {
userInteractionEnabled = true
}
override func touchesBegan(touch: CCTouch!, withEvent event: CCTouchEvent!) {
// This is the error line. I think it is caused by (applyImpulse(ccp(0, 400)) )
hero.physicsBody.applyImpulse(ccp(0, 400))
}
}
How can i simply fix this?
should i make a variable with applyImpulse?
I also tried to switch between CGPoint (ccp) and CCPackage, both didn't worked.
weak var hero: CCSprite!
This is incredibly dangerous and likely the cause of your problem. Besides using !, which is almost always to be avoided, this mixes it with weak. That means that if something else stops pointing to hero, this variable becomes an implicitly unwrapped nil. The next time you access it, you crash.
First, get rid of the !. If it needs to be weak, use ?. Beyond that, decide if it should really be strong. nothing you've shown here suggests that it should be weak.
I think the error code above can cause much confusion for new people because we don't know what is "optional" in swift 2.0 vs older versions of swift. For example I was getting the same error and could not tell where the problem was. What I found out is that I was making a call to a method using parenthesis () and in the same function I called the method without the parenthesis. This caused the error above. The () are an optional component that became optional with Swift 2.0 the way I understand it. You have to be consistent when calling the methods otherwise the compiler will throw the "Found nil error while unwrapping an optional value". Here is my code: The method I called inconsistently was NSDirectoryEnnumerationOptions(). This is corrected in the example I am sharing:
func listFilesWithFilter() -> [String]
{
NSFileManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
let musicUrl = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
do{
let fileList = try NSFileManager.defaultManager().contentsOfDirectoryAtURL(musicUrl,includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions())
print(fileList)
} catch let error as NSError {
print(error.localizedDescription)
}
// filter for wav files
do {
let directoryUrls = try NSFileManager.defaultManager().contentsOfDirectoryAtURL(musicUrl, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions())
print(directoryUrls)
let wavFiles = directoryUrls.filter(){ $0.pathExtension == "wav"}.map{ $0.lastPathComponent}
print ("WavFiles:\n" + wavFiles.description)
} catch let error as NSError {
print(error.localizedDescription)
}
return wavFiles
}

Resources