问题
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