I am currently trying to figure out a way to create a playlist from an array of avplayeritems and save the array to the nssuserdefaults but it wont work.
here is some code
AVAsset *asset = [AVAsset assetWithURL:_videoURL];
AAPLPlayerViewController __weak *weakSelf = self;
NSArray *oldItemsArray = [weakSelf.player items];
AVPlayerItem *newPlayerItem = [AVPlayerItem playerItemWithAsset:asset];
[weakSelf.player insertItem:newPlayerItem afterItem:nil];
[weakSelf queueDidChangeFromArray:oldItemsArray toArray:[self.player items]];
i am trying to create a playlist and store the AVPlayerItems from the queue of the AVQueuePlayer but since it has complex data that includes the AVPlayerItem and AVAsset it will crash when i try to save the [self.player items];
Ive also tried to store it to a Mutable dictionary but no methods ive tried have worked. Can anyone with experience suggest a good method of creating a playlist and storing it for the AVQueuePlayer?
I am using the AVFoundationQueuePlayer Objective C sample from the IOS developer downloads at this link :
https://developer.apple.com/library/ios/samplecode/AVFoundationQueuePlayer-iOS/Introduction/Intro.html#//apple_ref/doc/uid/TP40016104
Related
AVAsset *asset = [AVAsset assetWithUrl:#"myUrl.mp4"];
AVPlayerItem * item = [AVPlayerItem itemWithAsset:asset];
AVPlayer * player = [AVPlayer playerWithItem:item];
playerViewController.player = player;
[player play];
How Can i know that asset or item or whatever downloaded video fully.
I need it for future caching it;
Now im using
NSData * videoData = [NSData dataWithUrl:myurl.mp4"];
NSCache *cache = [NSCache new];
[cache setObject:videoData forKey:myUrl];
And when i retrieve data from nscache i write it to file and play
NSData *videoData = [cache objectForKey:myUrl];
[videoData writeToFile:MyPath.mp4 atomically:YES];
And then
NSURL *url = [NSURL fileUrlWithPath:mypath];
AVAsset *asset = =[AVAsset assetWithURL:url];
..etc and play
But it a little bit slow.
if videoData contains in AVAsset , i can store it or AVPlayerItem .But i need to know when it downloaded.
How can i implement caching in a different way or upgrade this one. Help.
we can download any data from cloud using NSURLSession, Download in progress and completion NSURLSession fires delegate methods , we can know download completion events and and progression events by using that delegate methods, you can implement downloading functionality by using NSURLSession as follows
https://www.raywenderlich.com/110458/nsurlsession-tutorial-getting-started
I have an app with vertical collection view of video items, each item should repeat itself continuously, until swiped up or down.
So I need not to stream file every time and not download files that were downloaded earlier.
I came up with slightly different approach:
Stream AVURLAsset,
When reached end I use AVAssetExportSession to save file to disk,
Then I create new AVPLayerItem with new AVAsset using saved file,
AVPlayer's replaceCurrentItem(with: <#T##AVPlayerItem?#>)
But this is lame, I guess. I have to steam file two times. First time on first run, and then then when saving file. I'd like to just cache AVAsset into memory for the current application session, so I don't need to keep files.
I have an AVQueuePlayer that is used to play a list of MP3 songs from the internet (http). I need to also know which song is currently playing. The current problem is that loading the song causes a delay that blocks the main thread while waiting for the song to load (first song as well as sequential songs after the first has completed playback).
The following code blocks the main thread:
queuePlayer = [[AVQueuePlayer alloc] init];
[queuePlayer insertItem: [AVPlayerItem playerItemWithURL:url] afterItem: nil]; // etc.
[queuePlayer play]
I am looking for a way to create a playlist of MP3s where the next file to be played back is preloaded in the background.
I tried the following code:
NSArray* tracks = [NSArray arrayWithObjects:#"http://example.com/song1.mp3", #"http://example.com/song2.mp3", #"http://example.com/song3.mp3", nil];
for (NSString* trackName in tracks)
{
AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:[NSURL URLWithString:trackName]
options:nil];
AVMutableCompositionTrack* audioTrack = [_composition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
NSError* error;
[audioTrack insertTimeRange:CMTimeRangeMake([_composition duration], audioAsset.duration)
ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio]objectAtIndex:0]
atTime:kCMTimeZero
error:&error];
if (error)
{
NSLog(#"%#", [error localizedDescription]);
}
// Store the track IDs as track name -> track ID
[_audioMixTrackIDs setValue:[NSNumber numberWithInteger:audioTrack.trackID]
forKey:trackName];
}
_player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
[_player play];
The issue with this is that I am not sure how to detect when the next song starts playing. Also, the docs don't specify whether or not this will pre-load MP3 files or not.
I am looking for a solution that:
Plays MP3s by pre-loading them in the background prior to playback (ideally start loading the next song before the current song finishes, so it is ready for immediate playback once the current song finishes)
Allow me to view the current song playing.
AVFoundation has some classes designed to do exactly what you're looking for.
It looks like your current solution is to build a single AVPlayerItem that concatenates all of the MP3 files that you want to play. A better solution is to create an AVQueuePlayer with an array of the AVPlayerItem objects that you want to play.
NSArray* tracks = [NSArray arrayWithObjects:#"http://example.com/song1.mp3", #"http://example.com/song2.mp3", #"http://example.com/song3.mp3", nil];
NSMutableArray *playerItems = [[NSMutableArray alloc] init];
for (NSString* trackName in tracks)
{
NSURL *assetURL = [NSURL URLWithString:trackName];
if (!assetURL) {
continue;
}
AVURLAsset* audioAsset = [[AVURLAsset alloc] initWithURL:assetURL
options:nil];
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:audioAsset];
[playerItems addObject:playerItem];
}
_player = [[AVQueuePlayer alloc] initWithItems:playerItems];
[_player play];
In answer to your final wrap-up questions:
Yes, AVQueuePlayer DOES preload the next item in the playlist while it's playing the current one.
You can access the currentItem property to determine which AVPlayerItem is currently playing.
I am building application in which online streaming is handled by AV Player(Default iOS player).
I want to add button for HD streaming, how to I achieve that?
The solution I found was to ensure that the underlying AVAsset is ready to return basic info, such as its duration, before feeding it to the AVPlayer. AVAsset has a method loadValuesAsynchronouslyForKeys: which is handy for this:
AVAsset *asset = [AVAsset assetWithURL:self.mediaURL];
[asset loadValuesAsynchronouslyForKeys:#[#"duration"] completionHandler:^{
AVPlayerItem *newItem = [[AVPlayerItem alloc] initWithAsset:asset];
[self.avPlayer replaceCurrentItemWithPlayerItem:newItem];
}];
In my case the URL is a network resource, and replaceCurrentItemWithPlayerItem: will actually block for several seconds waiting for this information to download otherwise.
I'm trying to make auto-play video in UITableViewCell depending on cell position.
I'm using the AVPlayer
Here is my code:
__weak typeof(self)this = self;
NSString* videoPath = #"http://test.com/test.mp4";
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:[NSURL URLWithString:videoPath] options:nil];
NSArray* keys = [NSArray arrayWithObjects:#"playable",nil];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^(){
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithAsset:asset];
this.avPlayer = [AVPlayer playerWithPlayerItem:playerItem];
this.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:this.avPlayer];
this.avPlayerLayer.frame = _videoContent.frame;
dispatch_async(dispatch_get_main_queue(),^{
[this.videoContent.layer addSublayer:this.avPlayerLayer];
[this.avPlayer play];
});
}];
But my UITableView is frozen when i scroll the table.
I think there are many time-consuming work but most biggest thing is
[this.avPlayer play]
So my question is that AVPlayer is the best way in this situation?
And is there any way to improve the performance?
Are you sure that creating the AVPlayerItem, AVPlayer, and AVPlayerLayer can all be performed off the main thread? You might want to try putting those inside the block that dispatches on the main queue.
Use the below link , this suits for your question.
https://github.com/PRX/PRXPlayer
I understand that when using a AVQueuePlayer to play a list of AVPlayerItem objects the player preload the next item in queue for faster reload when user get to this item.
The problem is that I need to have more control of which items preload, for example I want that the 3 next song and the 2 previous song be preloaded and prepare for fast loading.
So I think to manage the AVPlayerItem objects myself, I just not sure how do I preload a AVPlayerItem?
How can I preload the first 30 seconds for example?
Controlling the preload of the assets is a different problem than controlling the previous items. As soon as the AVQueuePlayer finishes an item, it'll release it from memory along with its cache. To get around that, you can add the AVPlayerItems into an array at the same time you add them into the player. This way once the Player removes the item, ARC will know there's still a reference to that object and not release it. Then you can simply put the item from the array back into the player and all the content will be loaded already. NOTE: you may want to limit the size of this cache array otherwise it will grow indefinitely if items are never removed from it.
If you want to have more control over the preloading, you can do so by loading the asset asynchronously and then creating the AVPlayerItem:
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:[NSURL URLWithString:url] options:nil];
NSArray *keys = #[#"playable", #"tracks",#"duration" ];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^()
{
// make sure everything downloaded properly
for (NSString *thisKey in keys) {
NSError *error = nil;
AVKeyValueStatus keyStatus = [asset statusOfValueForKey:thisKey error:&error];
if (keyStatus == AVKeyValueStatusFailed) {
return ;
}
}
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset];
dispatch_async(dispatch_get_main_queue(), ^ {
[player insertItem:item afterItem:nil];
});
}];