Simultaneously downloading and playing a song that is pieced together from multiple URLs

别来无恙 提交于 2019-12-11 12:49:31

问题


I have an NSArray of strings that are URLs. Each URL in the array points to data that is associated with a section of the song. I can play the full song with the following code, which fully downloads the song to a single file then plays it from that file:

// Get file path to store song locally
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [NSString stringWithFormat:@"%@/temp.mp3", [paths objectAtIndex:0]];

// Remove current temp file and create a new one
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
if ([fileManager fileExistsAtPath:filePath]) [fileManager removeItemAtPath:filePath error:&error];
[fileManager createFileAtPath:filePath contents:nil attributes:nil];
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];

// Initialize loop variables
NSMutableData *songData = nil;
NSUInteger totalLength = 0;
NSString *localURLString = [NSString stringWithFormat:@"file://%@", [filePath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURL *localURL = [NSURL URLWithString:localURLString];

for (NSString *stringURL in urls) {
    NSURL *url = [NSURL URLWithString:stringURL];
    songData = [NSMutableData dataWithContentsOfURL:url];
    totalLength += songData.length;
    [fileHandle writeData:songData];
    [fileHandle synchronizeFile];
}

[fileHandle closeFile];
self.player = [AVPlayer playerWithPlayerItem:[AVPlayerItem playerItemWithURL:localURL]];
[self.player play];

Now I'm trying to get the entire song to play seamlessly without downloading the whole thing first (so basically streaming it, but instead of streaming from one URL I have to piece the song together from multiple while I stream).

What options do I have?

UPDATE 1:

I've tried to generate the manifest file, there is no error writing the file, and the manifestString seems to be in the correct format, but the player does not play.

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *manifestPath = [NSString stringWithFormat:@"%@/manifest.m3u8", [paths objectAtIndex:0]];
NSMutableString *manifestString = [[NSMutableString alloc] init];
[manifestString appendString:@"#EXTM3\n"];
for (NSString *stringURL in urls) {
    [manifestString appendFormat:@"%@\n", stringURL];
}
[manifestString appendString:@"#EXT-X-ENDLIST"];
NSError *err = nil;
[manifestString writeToFile:manifestPath atomically:YES encoding:NSUTF8StringEncoding error:&err];
if (err) {
    NSLog(@"error writing manifest: %@", err);
}
NSString *manifestURLString = [NSString stringWithFormat:@"file://%@", [filePath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURL *manifestURL = [NSURL URLWithString:manifestURLString];
self.player = [AVPlayer playerWithPlayerItem:[AVPlayerItem playerItemWithURL:manifestURL]];
[self.player play];

回答1:


Since you're targeting iOS, have you considered using HTTP Live Streaming (HLS)? https://developer.apple.com/library/ios/documentation/networkinginternet/conceptual/streamingmediaguide/HTTPStreamingArchitecture/HTTPStreamingArchitecture.html

Although it's typically used for video + audio, you can create an audio-only manifest file on your server that lists each of the segments of the song sequentially and AVPlayer will take care of downloading it piece by piece automatically for you.

For example, I took a song (in a file called sample.mp3) and segmented it for use in HLS with ffmpeg:

ffmpeg -i sample.mp3 -acodec copy -map 0 -f segment -segment_time 5 -segment_list index.m3u8 segment%05d.mp3

This takes the input file (sample.mp3) and splits it into 5 second segments. It spits out a manifest file (index.m3u8 in this case):

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:6
#EXTINF:5.015511,
segment00000.mp3
#EXTINF:4.989389,
segment00001.mp3
#EXTINF:5.015511,
segment00002.mp3
#EXTINF:4.989389,
segment00003.mp3
#EXTINF:5.015511,
segment00004.mp3
#EXTINF:4.989378,
segment00005.mp3
#EXTINF:4.989389,
segment00006.mp3
#EXTINF:5.015511,
segment00007.mp3
#EXTINF:4.989389,
segment00008.mp3
#EXTINF:5.015511,
segment00009.mp3
#EXTINF:4.989389,
segment00010.mp3
#EXTINF:4.571433,
segment00011.mp3
#EXT-X-ENDLIST

If you pass a URL to the manifest to AVPlayer, it can do the rest.



来源:https://stackoverflow.com/questions/19102882/simultaneously-downloading-and-playing-a-song-that-is-pieced-together-from-multi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!