AVPlayer And Local Files

45,634

Solution 1

I decided to answer my own question because I felt like there is very little documentation on how to use the Apple provided AVPlayer for both local and stream (over http) files. To help understand the solution, I put together a sample project on GitHub in Objective-C and Swift The code below is Objective-C but you can download my Swift example to see that. It is very similar!

What I found is that the two ways of setting up the files are almost identical except for how you instantiate your NSURL for the Asset > PlayerItem > AVPlayer chain.

Here is an outline of the core methods

.h file (partial code)

-(IBAction) BtnGoClick:(id)sender;
-(IBAction) BtnGoLocalClick:(id)sender;
-(IBAction) BtnPlay:(id)sender;
-(IBAction) BtnPause:(id)sender;
-(void) setupAVPlayerForURL: (NSURL*) url;

.m file (partial code)

-(IBAction) BtnGoClick:(id)sender {

    NSURL *url = [[NSURL alloc] initWithString:@""];

    [self setupAVPlayerForURL:url];
}

-(IBAction) BtnGoLocalClick:(id)sender {

    // - - - Pull media from documents folder

    //NSString* saveFileName = @"MyAudio.mp3";
    //NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    //NSString *documentsDirectory = [paths objectAtIndex:0];
    //NSString *path = [documentsDirectory stringByAppendingPathComponent:saveFileName];

    // - - -

    // - - - Pull media from resources folder

    NSString *path = [[NSBundle mainBundle] pathForResource:@"MyAudio" ofType:@"mp3"];

    // - - -

    NSURL *url = [[NSURL alloc] initFileURLWithPath: path];

    [self setupAVPlayerForURL:url];
}

-(void) setupAVPlayerForURL: (NSURL*) url {
    AVAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
    AVPlayerItem *anItem = [AVPlayerItem playerItemWithAsset:asset];

    player = [AVPlayer playerWithPlayerItem:anItem];
    [player addObserver:self forKeyPath:@"status" options:0 context:nil];
}


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

    if (object == player && [keyPath isEqualToString:@"status"]) {
        if (player.status == AVPlayerStatusFailed) {
            NSLog(@"AVPlayer Failed");
        } else if (player.status == AVPlayerStatusReadyToPlay) {
            NSLog(@"AVPlayer Ready to Play");
        } else if (player.status == AVPlayerItemStatusUnknown) {
            NSLog(@"AVPlayer Unknown");
        }
    }
}

-(IBAction) BtnPlay:(id)sender {
    [player play];
}

-(IBAction) BtnPause:(id)sender {
    [player pause];
}

Check out the Objective-C source code for a working example of this. Hope this helps!

-Update 12/7/2015 I now have a Swift example of the source code you can view here.

Solution 2

I got AVPlayer to work with local URL by prepending file:// to my local url

NSURL * localURL = [NSURL URLWithString:[@"file://" stringByAppendingString:YOUR_LOCAL_URL]];
AVPlayer * player = [[AVPlayer alloc] initWithURL:localURL];

Solution 3

Try this

NSString*thePath=[[NSBundle mainBundle] pathForResource:@"yourVideo" ofType:@"MOV"];
NSURL*theurl=[NSURL fileURLWithPath:thePath];

Solution 4

Yes,thats possible to download and save the .mp3(or any kind of file)into NSDocument directory and then you can retrive from that and play by using AVAudioPlayer.

NSString *downloadURL=**your url to download .mp3 file**

NSURL *url = [NSURLURLWithString:downloadURL];

NSURLConnectionalloc *downloadFileConnection = [[[NSURLConnectionalloc] initWithRequest:      [NSURLRequestrequestWithURL:url] delegate:self] autorelease];//initialize NSURLConnection

NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,  YES) objectAtIndex:0];

NSString *fileDocPath = [NSStringstringWithFormat:@"%@/",docDir];//document directory path

[fileDocPathretain];

NSFileManager *filemanager=[ NSFileManager defaultManager ];

NSError *error;

if([filemanager fileExistsAtPath:fileDocPath])
{

//just check existence of files in document directory
}

NSURLConnection is used to download the content.NSURLConnection Delegate methods are used to  support downloading.

(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{

}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSFileManager *filemanager=[NSFileManagerdefaultManager];
if(![filemanager fileExistsAtPath:filePath])
{
[[NSFileManagerdefaultManager] createFileAtPath:fileDocPath contents:nil attributes:nil];

}
NSFileHandle *handle = [NSFileHandlefileHandleForWritingAtPath:filePath];

[handle seekToEndOfFile];

[handle writeData:data];

[handle closeFile];
 }

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
 {
 UIAlertView *alertView=[[UIAlertViewalloc]initWithTitle:@”"message:
 [NSStringstringWithFormat:@"Connection failed!\n Error - %@ ", [error localizedDescription]]   delegate:nilcancelButtonTitle:@”Ok”otherButtonTitles:nil];
  [alertView show];
  [alertView release];
  [downloadFileConnectioncancel];//cancel downloding
  }

Retrieve the downloaded Audio and Play:

   NSString *docDir1 = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,   NSUserDomainMask, YES) objectAtIndex:0];

   NSString *myfilepath = [docDir1 stringByAppendingPathComponent:YourAudioNameinNSDOCDir];

   NSLog(@”url:%@”,myfilepath);

   NSURL *AudioURL = [[[NSURLalloc]initFileURLWithPath:myfilepath]autorelease];

Just write your code to play Audio by using AudioURL

I Like to know if u have any clarification in this regard.

Thank you

Solution 5

Swift local playback version, assuming I have a file "shelter.mp3" in my bundle:

@IBAction func button(_ sender: Any?) {
    guard let url = Bundle.main.url(forResource: "shelter", withExtension: "mp3") else {
        return
    }

    let player = AVPlayer(url: url)

    player.play()
    playerView?.player = player;
}

See here for details about playerView or playing a remote url.

Share:
45,634
stitz
Author by

stitz

Updated on July 09, 2022

Comments

  • stitz
    stitz almost 2 years

    I am building a MP3 player for iOS that plays audio files hosted on the web. I want to offer the ability to play the files offline so I have the files downloading using ASIHTTP but I am cannot seem to find info on initiallzing AVPlayer with a mp3 in the app documents directory. Has anyone done this before? Is it even possible?

    *I posted an answer below that shows how to use the iOS AvPlayer for both local and http files. Hope this helps!

  • stitz
    stitz about 12 years
    Thank you for the sample code. I need to use AVPlayer instead of AVAudioPlayer for this project.
  • Pavel Alexeev
    Pavel Alexeev about 11 years
    Will it work fine if I'll try to play audio with AVPlayer immediately after starting request (or receiving first chunk)? What will happen if my download speed is not enough for realtime playback?
  • ChenSmile
    ChenSmile about 10 years
    NSString *path = [[NSBundle mainBundle] pathForResource:@"MyAudio" ofType:@"mp3"]; can u explain this line please.. from where u r fetching mp3..
  • Joshua Book
    Joshua Book about 9 years
    Hey @PavelAlexeev I'm trying to do a very similar thing now. Did you ever get something like this to work?
  • Pavel Alexeev
    Pavel Alexeev about 9 years
    No, but I've came across a library called “OrigamiEngine” – it is said to support HTTP data caching. Need to have a look on how it is implemented.
  • Pavel Alexeev
    Pavel Alexeev about 9 years
  • RenniePet
    RenniePet about 7 years
    The MPMoviePlayerController class is deprecated in iOS 9. developer.apple.com/reference/mediaplayer/…
  • Jonathan
    Jonathan about 7 years
    This fixed my issue. Make sure to check if adding "file://" to the beginning of your path fixes the issue.
  • Martin
    Martin over 6 years
    In stead of NSURL * localURL = [NSURL URLWithString:[@"file://" stringByAppendingString:YOUR_LOCAL_URL]]; you can write NSURL *localURL = [NSURL fileURLWithString:YOUR_LOCAL_URL];
  • Fattie
    Fattie about 4 years
    the question is about AVPlayer, NOT AVAudioPlayer