AVAsset from app sandbox - ios

I'm working with AVAsset in my app and met next problem.
When I'm writing something like this:
AVAsset *audioAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/Hello.mp3", [[NSBundle mainBundle] resourcePath]]]];
its work fine. But when I trying get fresh recorded file from my tmp directory from in app's sandbox like that:
AVAsset *audioAsset2 = [AVAsset assetWithURL:[NSURL URLWithString:[NSTemporaryDirectory() stringByAppendingPathComponent:[#"speechRecord" stringByAppendingPathExtension:#"m4a"]]]];
it doesn't work too. Even if I trying add video file to asset from sandbox - result is the same.
I even tried work with AVURLAsset, but asset always empty too. I need it to mix two audio files between themselves and then merge it with recorded video. If I can do that without AVAssets and there is another way, I will appreciate if You tell me. Or may there is some another function for that?

You create the second URL for audioAsset2 with the URLWithString selector. Your first asset loaded correctly, because you used the fileURLWithPath selector.
If you want to load a file at a given URL always create the NSURL object with the fileURLWithPath selector.
So simply try:
AVAsset *audioAsset2 = [AVAsset assetWithURL:[NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[#"speechRecord" stringByAppendingPathExtension:#"m4a"]]]];

Related

Local saved videos don't play again after app closes

This is strange, but basically I download and save a video locally, and the store the url path to provide to an AVPlayer to play.
This works fine the first time I do it. I download a file, and then I can play it to my hearts content as many times UNTIL I exit the app. When I launch the app a second time, I now get a black screen when I try to play the same exact video using the same exact path.
Because I am using the Simulator I can verify that the videos and pictures indeed very much still exist in the same folder I saved them to, and I can still play them if I click on them from the Finder.
Maybe it's a caching issue? If it matters, I've saved them straight to the Library directory as I test this.
Relevant Code:
NSString *outputFile = [NSString stringWithFormat:#"video_%#.mp4", guid];
NSString *outputDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *tempPath = [outputDirectory stringByAppendingPathComponent:outputFile];
NSURL *fileURL = [NSURL fileURLWithPath:tempPath];
// save the video to the URL
Then I "persist" it using an NSString [fileURL path] (The way I've built this out, assume the solution requires an NSString to NSURL conversion).
Later I create an AVPlayerItem:
NSURL *url = [NSURL fileURLWithPath:persistedObject.contentURL];
NSLog(#"url: %#", url); // prints a valid location**
AVPlayerItem *item = [AVPlayerItem playerItemWithURL:url];
** for example this is a sample url location
url: file:///Users/gabriel/Library/Developer/CoreSimulator/Devices/CE1FC933-808C-4003-9BE4-DEC59B787FF7/data/Containers/Data/Application/FAD072B4-B5B0-4487-8A76-57B047324A00/Library/picture_D8DEAFA5-0843-4AA3-BB32-C61E32D13579.mp4
It's been suggested I use URLForDirectory:inDomain:appropriateForURL:create:error: and URLByAppendingPathComponent: instead, which I will look into. But still confused as to why it would play when I first download it, but not after app exits when it's the same exact file.
You've made a classic mistake. You are persisting the full path. But the full path changes. Never persist a full path. Only persist the part of the path relative to the value obtained from NSSearchPathForDirectoriesInDomains.
Given what you are doing, you should only persist the base filename (outputFile). Then when the app starts, you rebuild the full path again like you did originally but use the persisted filename to append it to the dynamically obtained path to the application support folder.

what is avurlasset work and simplyfie this mehtod?

AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:assetURL options:#{AVURLAssetPreferPreciseDurationAndTimingKey:#YES}];
// audio asset url create object and specifies its method....
this audio asset can get value in only second?
I want to know how above code works and role of AVURLAsset
AVURLAsset is a subclass of AVAsset. AVAsset is used to get information about the asset such as metadata (like track titles, author, composer, and so on). The "asset" is usually a sound or video file.
In the example you have given, you are creating an AVAsset from a URL, and you are specifying that you want precise duration and timing. Because of that option, when you ask for the duration, there may be a significant amount of work required for the AVAsset method to compute a precise time. This is clearly stated in the Apple documentation. The documentation also suggests that you usually do not need the precise duration and timing.
The (no-)difference between AVAsset and AVURLAsset as of 2022-12-08:
https://developer.apple.com/documentation/avfoundation/avurlasset
This class is a concrete subclass of AVAsset. When you create an asset as shown below, the system creates and returns an instance of AVURLAsset.
let url: URL = // A local or remote asset URL.
let asset = AVAsset(url: url)

What is difference between URLWithString and fileURLWithPath of NSURL?

In my code I have to use URLWithString to play streaming(HLS) video and fileURLWithPath to play local video.
What is the difference between these two methods?
How should I use single method to play both videos.
Also I need to show last frame as still image when HSL video ends. Its now showing blank screen when it ends. How should i achieve this?
+URLWithString: produces an NSURL that represents the string as given. So the string might be #"http://www.google.com" and the URL represents http://www.google.com.
+fileURLWithPath: takes a path, not a URL, and produces an NSURL that represents the path using a file:// URL. So if you give it /foo/bar/baz the URL would represent file:///foo/bar/baz.
You can of course construct a file URL string manually and pass it to +URLWithString:, but +fileURLWithPath: is simpler to use when you already have a path, as you don't have to deal with escaping the string and coercing it to a URL format.
Similar thing happened in my app which use AVAudioPlayer. I tried with [NSURL URLWithString:path] and found out it fails to open certain mp3 files. I looked into error by a line like [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] fileTypeHint:AVFileTypeMPEGLayer3 error:&error], but the error was simply nil
However it was resolved by replacing the url with [NSURL fileURLWithPath:path].
In both case, the path path NSString * #"/var/mobile/Containers/Data/Application/4D96D4AE-2ED4-40B0-85D2-230E1AFA90E7/Documents/01-AudioTrack 01.mp3" 0x1457a8f0 Still I don't know the reason but now I should be careful using [NSURL URLWithString:].
PS. In NSURL Reference document, Apple said as below:
IMPORTANT
To create NSURL objects for file system paths, use fileURLWithPath:isDirectory: instead.
which clearly indicates [NSURL fileURLWithPath:] should be used for open file, though [NSURL URLWithString] also works for some cases.

how to get the physical path to the ALAsset object

Is there a way to turn the asset url returned by the following call to the physical path on the device?
NSURL *assetUrl = [_selectedAsset defaultRepresentation] url];
There is no way. (And even if you had the path to file, your app could not read the file because of sandboxing.)
The only way to get the raw data of an asset is getBytes:fromOffset:length:error: in ALAssetRepresentation.

Converting an iPhone IOS Video File Uploader to work with a file stored in document directory

This is my first real project. I have an app that captures several seconds of video using AVFoundation, outputs this to a file in the documents directory and lets the user preview the video before they upload it using HTTP and a PHP script on my website.
All the video capture and preview work perfectly but I am stuck on uploading the video file.
I learnt a lot from this simpleSDK video which shows how to achieve the desired effect using a video file stored in the apps main bundle.
The code from the tutorial that set up videoData ready to upload originally looked like this:
NSData *videoData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Movie" ofType:#"mov"]];
NSString *urlString = #"http://www.iphonedevnation.com/video-tutorial/upload.php";
The filename of the video file that I need to upload is always unique and generated using CFUUIDCreateString. I join this string to the path for the documents directory, add ".mov" to the end of it and save it into a text file for retrieving later.
This all works as I am able to retrieve the filename from the file and use it to preview the movie clip elsewhere in the app.
My path is in an NSString, that I have tried converting to NSURL and removing the file suffix to get it to work with the NSData *videoData.........line but it doesn't compile, I get an "No known class method for selector 'dataWithContentsOfFile:ofType.' error. I am targeting iOS 5 and using Xcode 4.3 with ARC and Storyboards.
I've been at this for best part of 5 hours now so hopefully someone can help. My code, which included tips from elsewhere on converting from a NSString to NSURL follows:
NSString *content = [[NSString alloc] initWithContentsOfFile:lastSavedTalentFilenamePath
usedEncoding:nil
error:nil];
NSLog(#"content=%#",content);
//Need to now remove the '.mov' file type identifier
NSString *shortContent= [content substringToIndex:[content length]-4];
NSLog(#"***************shortContent***************%#", shortContent);
NSURL *convertedContent = [NSURL fileURLWithPath:shortContent];
NSLog(#"***************convertedContent***********%#",convertedContent);
NSData *videoData = [NSData dataWithContentsOfFile:convertedContent ofType:#"mov"];];
There is no NSData method called dataWithContentsOfFile:ofType:
The methods available are:
+ dataWithContentsOfFile:
+ dataWithContentsOfFile:options:error:
both of which take the file location as an NSString so there's not need to convert to an NSURL

Resources