Playing video from within app? - ios

I am trying to play a local video from my app using AVPlayer. I have looked everywhere but can't find any useful tutorials/demos/documentation. Here is what I am trying, but it is not playing. Any idea why? The URL is valid because I was using the same one to play a video using MPMoviePlayer successfully.
Video *currentVideo = [videoArray objectAtIndex:0];
NSString *filepath = currentVideo.videoURL;
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
AVURLAsset *asset = [AVURLAsset assetWithURL: fileURL];
AVPlayerItem *item = [AVPlayerItem playerItemWithAsset: asset];
self.player = [[AVPlayer alloc] initWithPlayerItem: item];
AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
layer.frame = CGRectMake(0, 0, 1024, 768);
[self.view.layer addSublayer: layer];
[self.player play];

I believe the problem is that you're assuming that after executing this line AVURLAsset *asset = [AVURLAsset assetWithURL: fileURL]; the asset is ready to use. This is not the case as noted in the AV Foundation Programming Guide:
You create an asset from a URL using AVURLAsset. Creating the asset, however,
does not necessarily mean that it’s ready for use. To be used, an asset must
have loaded its tracks.
After creating the asset try loading it's tracks:
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
NSString *tracksKey = #"tracks";
[asset loadValuesAsynchronouslyForKeys:#[tracksKey] completionHandler:
^{
NSError *error;
AVKeyValueStatus status = [asset statusOfValueForKey:tracksKey error:&error];
if (status == AVKeyValueStatusLoaded) {
// At this point you know the asset is ready
self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
...
}
}];
Please refer to this link to see the complete example.
Hope this helps!

Related

custom resourceLoader with AVComposition

Is there any way to use a custom resourceLoader with an AVComposition? I get the AVAssetResourceLoaderDelegate callbacks when I set the resourceLoader on an AVURLAsset and create an AVPlayerItem with that asset. But if I use that same AVURLAsset in an AVComposition, I don't get the delegate callbacks. In fact it never returns from the call to insert the asset into the composition.
AVAssetResourceLoaderDelegate methods called with AVURLAsset:
NSURL* mungedURL = [self mungeURL:itemURL];
AVURLAsset* asset = [[AVURLAsset alloc] initWithURL:mungedURL options:nil];
[asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
AVAssetResourceLoaderDelegate methods NOT called with AVURLAsset inserted into AVComposition:
NSURL* mungedURL = [self mungeURL:itemURL];
AVURLAsset* asset = [[AVURLAsset alloc] initWithURL:mungedURL options:nil];
[asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
AVMutableComposition* composition = [AVMutableComposition composition];
CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
[composition insertTimeRange:timeRange ofAsset:asset atTime:kCMTimeZero error:nil];
self.playerItem = [AVPlayerItem playerItemWithAsset:composition];
(actually, it hangs at insertTimeRange:ofAsset:atTime:error. I guess it tries to load from the munged url at that point - but doesn't use delegate.)
Method to tweak url scheme so resource loader delegate is called:
- (NSURL*)mungeURL:(NSURL*)url
{
NSURLComponents* components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
components.scheme = #"fake-scheme";
return [components URL];
}

How to play mp3 file from url in iOS?

I am trying to play mp3 file located somewhere on remote server.I have the url of that music fileI have tried it playing it using AVAudioPlayer or AVPlayer but i am not able to play the mp3 file.Please tell me how can i play the mp3 file.
code to play music:
NSString *aSongURL = [NSString stringWithFormat:#"http://megdadhashem.wapego.ru/files/56727/tubidy_mp3_e2afc5.mp3"];
// NSLog(#"Song URL : %#", aSongURL);
AVPlayerItem *aPlayerItem = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:aSongURL]];
AVPlayer *anAudioStreamer = [[AVPlayer alloc] initWithPlayerItem:aPlayerItem];
[anAudioStreamer play];
// Access Current Time
NSTimeInterval aCurrentTime = CMTimeGetSeconds(anAudioStreamer.currentTime);
// Access Duration
NSTimeInterval aDuration = CMTimeGetSeconds(anAudioStreamer.currentItem.asset.duration);
Please tell me how do i do it?
Try Below Code.
NSURL *url = [NSURL URLWithString:#"http://megdadhashem.wapego.ru/files/56727/tubidy_mp3_e2afc5.mp3"];
self.playerItem = [AVPlayerItem playerItemWithURL:url];
self.player = [AVPlayer playerWithPlayerItem:playerItem];
self.player = [AVPlayer playerWithURL:url];
[self.player play];
Try use AVAudioPlayer, see below
NSString *aSongURL = [NSString stringWithFormat:#"http://megdadhashem.wapego.ru/files/56727/tubidy_mp3_e2afc5.mp3"];
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:aSongURL] error:nil];
[audioPlayer play];
Hope it works.
Cheers.

AVQueuePlayer gapless playback

I am trying to dynamically add .aac chunks (usually 10 seconds) during the playback to AVQueuePlayer to mimic the AVPlayer hls playback.
However it plays songs one after another as I wished, there is about 200ms to 400 ms gap between songs.
following question seems to have the answer it to this question but it doesn't work for me.
AVQueuePlayer playback without gap and freeze
I have a singleton player and a singleton avplayeritem to keep track of the last item.
then with following code I can successfully play the songs with gap.
NSURL *url = [NSURL URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
//NSData *urlData = [NSData dataWithContentsOfURL:url];
GlobalPlayer *singleton=[GlobalPlayer sharedManager];
//AVPlayerItem *item=[AVPlayerItem playerItemWithURL:url];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil];
NSArray *keys = [NSArray arrayWithObject:#"playable"];
if (singleton.lastItem==nil) {
//initilize player
//NSArray *playerArray=[[NSArray alloc] initWithObjects:item, nil];
//singleton.globPlayer=[[AVQueuePlayer alloc] initWithItems:playerArray];
//[singleton.globPlayer play];
singleton.globPlayer=[[AVQueuePlayer alloc] init];
singleton.lastItem=[AVPlayerItem alloc];
__block AVPlayerItem *playerItem;
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^()
{
dispatch_async(dispatch_get_main_queue(), ^
{
playerItem = [[AVPlayerItem alloc] initWithAsset:asset];
[singleton.globPlayer insertItem:playerItem afterItem:nil];
singleton.lastItem=playerItem;
[singleton.globPlayer play];
});
}];
}
else
{
//[singleton.globPlayer insertItem:item afterItem:singleton.lastItem];
__block AVPlayerItem *playerItem;
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^()
{
dispatch_async(dispatch_get_main_queue(), ^
{
playerItem = [[AVPlayerItem alloc] initWithAsset:asset];
[singleton.globPlayer insertItem:playerItem afterItem:singleton.lastItem];
singleton.lastItem=playerItem;
});
}];
}
Do I have to decode the chunks then feed the PCM to AVQueuePlayer? If that is the only solution how do I feed NSData that holds pcm to the AVPlayerItem ?

Play song from ipod library with superpowered

since Apple anounced that every app has to support 64-bit starting February 1rst, I can't use Dirac3LE anymore. So I found Superpowered which seems to do the same. The only problem I currently see is, that I can't get it to play songs from the iPod Library.
I've tried importing the song via AVAssetExportSession but can't get it to work. This is the code I've tried so far:
NSURL *url = [playingSong valueForProperty:MPMediaItemPropertyAssetURL];
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:url options:nil];
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset: songAsset presetName: AVAssetExportPresetPassthrough];
exporter.outputFileType = #"com.apple.coreaudio-format";
NSString *fname = [[NSString stringWithFormat:#"tmp"] stringByAppendingString:#".mp3"];
NSString *tempPath = NSTemporaryDirectory();
NSString *exportFile = [tempPath stringByAppendingPathComponent: fname];
exporter.outputURL = [NSURL fileURLWithPath:exportFile];
[exporter exportAsynchronouslyWithCompletionHandler:^{
self.player = [[SuperpoweredAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:exportFile]];
[self.player play];
}];
With opening the file via:
player->open([[url path] fileSystemRepresentation]);
Even if this would work, I'm kind of concerned if this would be fast enough for a music player. Importing a song, as soon as the other finished.
Are there any other options?
Thanks!
if you have a MPMediaItem *item got from iTunes Library, you can use:
player->open([[item assetURL].absoluteString UTF8String]);

AVAssetResourceLoaderDelegate setup issue

I have a weird issue when trying to setup AVAssetResourceLoaderDelegate. When using this code it works most of the time on a device but it doesn't work on the simulator at all:
NSURL *url = [NSURL URLWithString:#"xxx://name"];
AVURLAsset *asset = [AVURLAsset assetWithURL:url];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
[asset.resourceLoader setDelegate:self queue:self.queue];
AVPlayer *avPlayer = [AVPlayer playerWithPlayerItem:playerItem];
[avPlayer play];
The issue is that the delegate method is never getting called:
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
However, this code works perfectly fine:
NSURL *url = [NSURL URLWithString:#"xxx://name"];
AVURLAsset *asset = [AVURLAsset assetWithURL:url];
[asset.resourceLoader setDelegate:self queue:self.queue];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
AVPlayer *avPlayer = [AVPlayer playerWithPlayerItem:playerItem];
[avPlayer play];
The only difference is that we set the delegate first and then we create AVPlayerItem with the asset. In the first case, the asset is not being copied when creating AVPlayerItem and if we check playerItem.asset.resourceLoader.delegate the delegate is set correctly but it's never getting called.
I would appreciate any help with it.
Thanks,
Michal

Resources