AVPlayer和本地文件

21

我正在为iOS构建一个MP3播放器,可以播放网络上托管的音频文件。我想提供离线播放文件的能力,所以我正在使用ASIHTTP下载文件,但我似乎找不到有关在应用程序文档目录中使用mp3初始化AVPlayer的信息。是否有人以前做过这个?这是可能的吗?

*我在下面发布了一个答案,展示如何同时使用iOS AvPlayer播放本地和http文件。希望对你有所帮助!


你考虑过使用内部的sqlite而不是文档目录吗? - rwyland
7个回答

36
我决定回答自己的问题,因为我觉得关于如何使用由苹果提供的AVPlayer播放本地和流媒体文件(通过HTTP)的文档非常少。为了帮助理解解决方案,我在GitHub上创建了一个Objective-C和Swift示例项目(Objective-C)(Swift)。下面的代码是Objective-C,但你可以下载我的Swift示例查看它。它们非常相似!
我发现两种设置文件的方法几乎相同,除了如何实例化你的NSURL用于Asset > PlayerItem > AVPlayer链。
以下是核心方法的概要
.h文件(部分代码)
-(IBAction) BtnGoClick:(id)sender;
-(IBAction) BtnGoLocalClick:(id)sender;
-(IBAction) BtnPlay:(id)sender;
-(IBAction) BtnPause:(id)sender;
-(void) setupAVPlayerForURL: (NSURL*) url;

.m文件(部分代码)

-(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];
}

请查看Objective-C源码的实际应用例子。

-更新于12/7/2015,我现在有一份Swift版本的源码示例,您可以在此查看


NSString *path = [[NSBundle mainBundle] pathForResource:@"MyAudio" ofType:@"mp3"]; 请问您能解释一下这行代码吗?从哪里获取MP3文件呢? - ChenSmile

19

我通过在本地URL前添加file://来使得AVPlayer可以使用本地URL

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

这解决了我的问题。请确保检查是否在路径开头添加“file://”以解决问题。 - Jonathan
1
你可以使用以下代码替换NSURL * localURL = [NSURL URLWithString:[@"file://" stringByAppendingString:YOUR_LOCAL_URL]];:NSURL *localURL = [NSURL fileURLWithString:YOUR_LOCAL_URL]; - Martin

3
是的,可以将.mp3(或任何类型的文件)下载并保存到NSDocument目录中,然后您可以通过使用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
  }

获取已下载的音频并播放:

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

   NSString *myfilepath = [docDir1 stringByAppendingPathComponent:YourAudioNameinNSDOCDir];

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

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

只需编写代码,通过使用AudioURL播放音频。

我想知道您是否有任何相关的澄清。

谢谢


谢谢您提供示例代码。我需要在这个项目中使用AVPlayer而不是AVAudioPlayer。 - stitz
如果我在开始请求(或接收第一个块)后立即尝试使用AVPlayer播放音频,它会正常工作吗?如果我的下载速度不足以进行实时播放,会发生什么? - Pavel Alexeev
1
嘿,@PavelAlexeev,我现在正在尝试做类似的事情。你有没有成功运行类似的东西? - Joshua Book
没有,但我遇到了一个叫做“OrigamiEngine”的库——据说它支持HTTP数据缓存。需要看一下它是如何实现的。 - Pavel Alexeev
再提供一个链接:http://code4app.net/ios/NCMusicEngine-Pro/518657716803facd2d000000 - Pavel Alexeev
问题是关于AVPlayer,而不是AVAudioPlayer。 - Fattie

3

试试这个

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

1

假设我在我的资源包中有一个名为 "shelter.mp3" 的文件,这是 Swift 本地播放版本:

@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;
}

点击此处查看有关playerView或播放远程URL的详细信息。


0

使用 Avplayer 播放歌曲非常困难,为什么不使用 MPMoviePlayerController 播放器。我已经从文档目录中播放了歌曲。我将发布代码,请参考此代码,它可以正常工作。您也可以直接从 URL 播放歌曲。

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *publicDocumentsDir = [paths objectAtIndex:0];   
NSString *dataPath = [publicDocumentsDir stringByAppendingPathComponent:@"Ringtone"];
NSString *fullPath = [dataPath stringByAppendingPathComponent:[obj.DownloadArray objectAtIndex:obj.tagvalue]];
[[UIApplication sharedApplication] setStatusBarHidden:NO animated:NO];


NSURL *url = [NSURL fileURLWithPath:fullPath];

videoPlayer =[[MPMoviePlayerController alloc] initWithContentURL: url];
[[videoPlayer view] setFrame: [self.view bounds]]; 
[vvideo addSubview: [videoPlayer view]];


videoPlayer.view.frame=CGRectMake(0, 0,260, 100);
videoPlayer.view.backgroundColor=[UIColor clearColor];
videoPlayer.controlStyle =   MPMovieControlStyleFullscreen;
videoPlayer.shouldAutoplay = YES;  
[videoPlayer play];
videoPlayer.repeatMode=YES;


NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:@selector(moviePlayerEvent:) name:MPMoviePlayerLoadStateDidChangeNotification object:videoPlayer];


/*  NSNotificationCenter *notificationCenter1 = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:@selector(moviePlayerEvent1:) name:MPMoviePlaybackStateStopped object:videoPlayer];
*/
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(playbackStateChange:)
                                             name:MPMoviePlayerLoadStateDidChangeNotification
                                           object:videoPlayer];
}

-(void)playbackStateChange:(NSNotification*)notification{

if([[UIApplication sharedApplication]respondsToSelector:@selector(setStatusBarHidden: withAnimation:)])
  { 
      [[UIApplication sharedApplication] setStatusBarHidden:NO 
                                            withAnimation:UIStatusBarAnimationNone];
   }
  else 
   {

       [[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
   }
}

 -(void)moviePlayerEvent:(NSNotification*)aNotification{


   [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:NO];


}

  -(void)moviePlayerEvent1:(NSNotification*)aNotification{

[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:NO];

 }

MPMoviePlayerController类在iOS 9中已被弃用。https://developer.apple.com/reference/mediaplayer/mpmovieplayercontroller - RenniePet

0
我观察到的是,你需要正确的文件扩展名,否则你会看到一个带有被划掉的播放器图标的黑屏。 你需要给你下载的文件添加一个像.m4v或.mov这样的文件扩展名。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接