Creating a AVAsset with a HTTP NSURL - iphone

I'm trying to merge two NSURLs that contain video references. One of the urls point to a video on AWS and the other points to a video that is stored locally. My exporting code works because I've tried it with two local videos, but whenever I try merge the HTTP url and the local url I get this error: Error Domain=NSURLErrorDomain Code=-1100 "The requested URL was not found on this server." UserInfo=0x155d2f20 {NSUnderlyingError=0x155b4f60 "The operation couldn’t be completed. No such file or directory", NSLocalizedDescription=The requested URL was not found on this server.}
This is the code to create the AVAssets:
AVAsset *firstAsset = [AVAsset assetWithURL:awsURL];
Does AVAssetExportSession require local urls to be used?

#MichaelScaria, many thanks for posting what you figured out, i was on this for about 3 days. below is my solution in full when i was trying to get AVAssets from both local urls and remote urls
+ (AVAsset*)getAVAssetFromRemoteUrl:(NSURL*)url
{
if (!NSTemporaryDirectory())
{
// no tmp dir for the app (need to create one)
}
NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:#"temp"] URLByAppendingPathExtension:#"mp4"];
NSLog(#"fileURL: %#", [fileURL path]);
NSData *urlData = [NSData dataWithContentsOfURL:url];
[urlData writeToURL:fileURL options:NSAtomicWrite error:nil];
AVAsset *asset = [AVAsset assetWithURL:fileURL];
return asset;
}
+ (AVAsset*)getAVAssetFromLocalUrl:(NSURL*)url
{
AVURLAsset *asset = [AVAsset assetWithURL:url];
return asset;
}

I saved the online url to a temporary directory and used the temporary url to merge the video and it worked.
NSData *urlData = [NSData dataWithContentsOfURL:initalURL];
[urlData writeToFile:path options:NSAtomicWrite error:nil]

Maybe you need to use AVURLAsset or other subclasses instead? From the docs:
You often instantiate an asset using AVURLAsset—a concrete subclass of AVAsset—with NSURLs that refer to audiovisual media resources, such as streams (including HTTP live streams), QuickTime movie files, MP3 files, and files of other types. You can also instantiate an asset using other concrete subclasses that extend the basic model for audiovisual media in useful ways, as AVComposition does for temporal editing.

Related

How to access image from Asset URL in iPhone?

I am getting asset URL from NSURL* localUrl = (NSURL *)[info valueForKey:UIImagePickerControllerReferenceURL]; and I saved it in a local database. And at the time of retrieving I have got an string and I have convert it into NSURL through NSURL *url1 = [NSURL URLWithString:image_path]; but when I get NSData from this URL through NSData *myData = [NSData dataWithContentsOfURL:url1]; it return NULL. Can anyone help me to get NSData and convert it into image.
You can not convert it direct. You will have to use ALAsset Block. Here is the complete description for same thing.
display image from URL retrieved from ALAsset in iPhone

How to play a NSData in video player

I have written an async call to download a video of mp4 format. The response result is an NSData. How can I open the NSData in any video player framework which should be supported in IOS 3.
An NSData is basically a container object, and thus not in a format you can play in a video player. Without seeing any code, or the results of your data, you can create an NSString from data with
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
Now that you have a string, you can create an NSURL with
NSURL *movieURL = [NSURL URLWithString:dataString];
From there, you should be able to pass this into an MPMoviePlayerController with
MPMoviePlayerController *moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
It's not possible to directly play the NSData into AVPlayer. What you can do is download the Data into Document folder and later fetch the file path and give that path to AVPlayer.

Is there a way to extract embedded image data from an mp3 in ios

I understand that mp3s sometimes contain album artwork (in my case, I'm working with podcast files). Is there a way in iOS to extract the image data from an mp3 file?
MP3s, including podcasts, do often have embedded metadata, including artwork. The easiest way to get the embedded metadata (for MP3s not in the iTunes library) is through the AVAsset class. If you are trying to get metadata over a network use the AVURLAsset instead, but accessing the metadata is the same with either.
AVAsset has an NSArray property named commonMetadata which contains instances of the class AVMetadataItem. You can iterate over this array to find the element with the commonKey of(usually) "artwork" The value property of this AVMetadataItem should be an NSDictionary of data about the artwork. Within this dictionary you will find the key "data" which should contain data you can use to construct a UIImage. This is quite nested and this description is admittedly confusing. So here is a code example.
NSURL *url = <# url of resource here #>;
AVAsset *asset = [AVAsset assetWithURL:url];
for (AVMetadataItem *metadataItem in asset.commonMetadata) {
if ([metadataItem.commonKey isEqualToString:#"artwork"]){
NSDictionary *imageDataDictionary = (NSDictionary *)metadataItem.value;
NSData *imageData = [imageDataDictionary objectForKey:#"data"];
UIImage *image = [UIImage imageWithData:imageData];
// Display this image on my UIImageView property imageView
self.imageView.image = image;
}
}
Again this is a very simple example of how to load from a local resource; If you are loading this over a network you should use an AVURLAsset. Also be careful of the blocking nature of this call.
Take a look at Apple's sample AddMusic project and you'll see how they get the album artwork via MPMediaItem & MPMediaItemArtwork objects.
-(UIImage *)getMP3Pic:(NSURL *)url
{
AVAsset *asset = [AVAsset assetWithURL:url];
for (AVMetadataItem *metadataItem in asset.commonMetadata) {
if ([metadataItem.commonKey isEqualToString:#"artwork"]){
return [UIImage imageWithData:(NSData *)metadataItem.value];
}
}
}

How to play movie files with no file extension on iOS with MPMoviePlayerController or AVPlayer?

I want to play a movie in iOS 4.3 on the iPad. I've successfully used MPMoviePlayerController and AVPlayer to load files from a remote URL when the filename has a file extension. However, when I use a CDN that doesn't return the filename (just an un-guessable random name), neither MPMoviePlayerController or AVPlayer seem to be able to cope.
Is there a way to tell either player that it really is a movie of type x and it should just get on playing it?
MPMoviePlayerController will return the following error from it's changed state notification:
{
MPMoviePlayerPlaybackDidFinishReasonUserInfoKey = 1;
error = "Error Domain=MediaPlayerErrorDomain Code=-12847 \"This movie format is not supported.\" UserInfo=0x5b60030 {NSLocalizedDescription=This movie format is not supported.}";
}
I know that file is a valid m4v file, as when I rename it all is fine.
File at tmp
NSString* _filePath
Create symlink
NSFileManager *filemgr = [NSFileManager defaultManager];
NSString *slink = [_filePath stringByAppendingPathExtension:#"m4v"];
if (![filemgr fileExistsAtPath:slink]) {
NSError *error = nil;
[filemgr createSymbolicLinkAtPath:[_filePath stringByAppendingPathExtension:#"m4v"] withDestinationPath: _filePath error: &error];
if (error) {
...
}
}
...
play video by slink
If the player can't guess the file format you need to check that the CDN sends the right mime type back. My guess is that your CDN can't guess the mimetype correctly nor can the player.
In most cases this is due to how the CDN presents the HTTP header. Check that the "Content-Type" header is set to a video format matching your content.
WebKit handle this by a Private AVURLAsset option: AVURLAssetOutOfBandMIMETypeKey, this option is used when you specify a MIME type in the HTML's video tag,
You can use this option like:
NSString * mimeType = #"video/mp4";
// or even with codecs
mimeType = #"video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"";
// create asset
AVURLAsset * asset = [[AVURLAsset alloc] initWithURL:url options:#{#"AVURLAssetOutOfBandMIMETypeKey": mimeType}];
// create AVPlayer with AVURLAsset
AVPlayer * player = [AVPlayer playerWithPlayerItem:[AVPlayerItem playerItemWithAsset:asset]];
Since it is a private key, you may want to obfuscate it if you plan to submit it to AppStore.
The WebKit source can be found here:
https://opensource.apple.com/source/WebCore/WebCore-7604.1.38.1.6/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm.auto.html
Finally, I found the answer.
You should use AVURLAsset (the subclass of AVAsset) and set the MIMEType in the options input :
let mimeType = "video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\""
let urlAsset = AVURLAsset(url: url, options: ["AVURLAssetOutOfBandMIMETypeKey": mimeType])
Source -> https://stackoverflow.com/a/54087143/6736184
iPhone support video H.264, MPEG-4 in .mp4, .m4v, .mov formats and audio files in AAC, MP3, M4a, Apple lossless and Audible.
You can use NSFileManager's -contentsOfDirectoryAtPath:error: method to get an array with the contents of a directory (as strings).Then you just do strings operations .
Dylan is correct.
Both MPMoviePlayer and AVPlayer needs a file extension in order to play the file from URL otherwise an error message will be shown. Better to use some kind of tricks.
If you have problems to get the ContentType of your connection you could cycle through the playable MIME types and create symbolic links to the actual file with the extension and check if they are playable. Like so:
NSLog(#"linked path: %#",[videoURL absoluteString]);
NSString* linkedPath;
AVURLAsset* asset;
NSFileManager *filemgr = [NSFileManager defaultManager];
for (NSString* string in [AVURLAsset audiovisualMIMETypes]) {
if ([string containsString:#"video/"]) {
NSLog(#"Trying: %#",string);
linkedPath = [[videoURL absoluteString] stringByAppendingPathExtension:[string stringByReplacingOccurrencesOfString:#"video/" withString:#""]];
NSLog(#"linked path: %#",linkedPath);
if (![filemgr fileExistsAtPath:linkedPath]) {
NSError *error = nil;
[filemgr createSymbolicLinkAtURL:[NSURL URLWithString:linkedPath] withDestinationURL:videoURL error:&error];
if (error) {
NSLog(#"error %#",error.localizedDescription);
}
}
asset = [AVURLAsset assetWithURL:[NSURL URLWithString:linkedPath]];
if ([asset isPlayable]) {
NSLog(#"Playable");
break;
}else{
NSLog(#"Not Playable");
asset = nil;
}
}
}
It's sort of a hack, but what you could do is run each name through a method that checks for a period with three characters after it. If not, just append .m4v automatically. Or get the MIME type and append an extension automatically based on the returned type. If available. Look up documentation with NSString for more info. Good luck! Let me know if that helped.

How to play audio file on websites on iPhone?

I want to play an audio file which is posted on a website. I'm trying to use AVAudioPlayer and set the url to its website link. But the bgPlayer turns out to be nil. I think I can download this audio file and play it afterwards, but is there any way to play it while I'm downloading it?
NSURL *bgURL = [NSURL URLWithString:#"http://www.radioslots.com/iphone/test/tmp/1.mp3"];
bgPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:bgURL error:nil];
bgPlayer.numberOfLoops = -1;
if (bgPlayer) {
[bgPlayer play];
}
AVAudioPlayer isn't made to open network streams, I could be mistaken but I'm pretty sure it's not possible.
Just off the top of my head, I can think of two ways that would probably work:
1. Use MPMoviePlayer, as this can open network streams and despite the name works with audio. The only thing is this pops up the modal player with controls.
2. Download the network file and store it locally, then use AVAudioPlayer to play the local file.
I have just written answer here.Check it and replace the url used there with yours..
you just replace
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"songname" ofType:#"mp3"];
NSURL *newURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
with
NSString *soundFilePath = #"Your URL";
NSURL *newURL = [[NSURL alloc] initWithString: soundFilePath];
There is a proper documentation available at this link
But I think you should also check the error code you are getting by this way:
NSError *error;
bgPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:bgURL error:&error];
Hope this helps.