最近在做的項(xiàng)目里有一個(gè)功能,就是拿到手機(jī)媒體庫(kù)中的音頻文件伦籍,并實(shí)現(xiàn)APP中的播放蓝晒,已經(jīng)轉(zhuǎn)成MP3格式上傳到服務(wù)器上。
首先是要能獲取到ipod library中的音頻帖鸦。這里我用的是MPMediaQuery芝薇,在這里有一個(gè)坑,可以拿到的歌曲中有很多歌曲的AssetURL為nil作儿,這是因?yàn)镸PMediaQuery只能拿到用戶通過(guò)itunes倒入進(jìn)去的歌曲url洛二。
代碼如下:
// 1.創(chuàng)建媒體選擇隊(duì)列(從ipod庫(kù)中讀出音樂(lè)文件)
MPMediaQuery*everything = [[MPMediaQueryalloc]init];
// 2.創(chuàng)建讀取條件(類似于對(duì)數(shù)據(jù)做一個(gè)篩選) Value:作用等同于MPMediaType枚值
MPMediaPropertyPredicate*albumNamePredicate =
[MPMediaPropertyPredicate predicateWithValue:[NSNumber numberWithInt:MPMediaTypeMusic ] forProperty: MPMediaItemPropertyMediaType];
//3.給隊(duì)列添加讀取條件
[everythingaddFilterPredicate:albumNamePredicate];
//4.從隊(duì)列中獲取符合條件的數(shù)組集合
NSArray*itemsFromGenericQuery = [everythingitems];
//5.便利解析數(shù)據(jù)
for(MPMediaItem*songinitemsFromGenericQuery) {
//歌曲名字
> NSString *songTitle = [song valueForProperty: MPMediaItemPropertyTitle];
//歌曲路徑
NSString *url = [song valueForProperty: MPMediaItemPropertyAssetURL];
//歌手
NSString *songer = [song valueForProperty: MPMediaItemPropertyArtist];
}
拿到后肯定是實(shí)現(xiàn)APP中的播放,這個(gè)就很簡(jiǎn)單了攻锰。采用AVAudioPlayer就好了
接著就是重點(diǎn)了晾嘶。項(xiàng)目需要把該音頻上傳到服務(wù)器,但是拿到的AssetURL并不支持后臺(tái)上傳娶吞,它是這樣的:pod-library://item/item.m4a?id=8461911140233300129***
經(jīng)過(guò)一番查閱垒迂,最終找到一個(gè)辦法,就是先把它轉(zhuǎn)為caf 寫(xiě)到內(nèi)存里妒蛇,然后再把.caf轉(zhuǎn)為.mp3 就可以上傳了机断。這里caf轉(zhuǎn)mp3需要使用第三方庫(kù):lame (lame三庫(kù)的資源)
代碼如下:
1.導(dǎo)出成caf格式,這種導(dǎo)出方式绣夺,文件名必須以.caf作為后綴
- (void)convertToCAF:(NSString *)songUrl name:(NSString *)songName
{
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[UsingHUD showInView:self.view text:@"正在處理毫缆,請(qǐng)稍等..."];
});
NSURL *url = [NSURL URLWithString:songUrl];
//由于中文歌名不行 這邊采用時(shí)間戳
NSString *fileName = [NSString stringWithFormat:@"%@.caf",[self getTimestamp]];
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:url options:nil];
NSError *assetError = nil;
AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:songAsset
error:&assetError];
if (assetError) {
NSLog (@"error: %@", assetError);
return;
}
AVAssetReaderOutput *assetReaderOutput = [AVAssetReaderAudioMixOutput
assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks
audioSettings: nil];
if (! [assetReader canAddOutput: assetReaderOutput]) {
NSLog (@"can't add reader output... die!");
return;
}
[assetReader addOutput: assetReaderOutput];
NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [dirs objectAtIndex:0];
NSString *exportPath = [documentsDirectoryPath stringByAppendingPathComponent:fileName];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) {
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}
NSURL *exportURL = [NSURL fileURLWithPath:exportPath];
AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:exportURL
fileType:AVFileTypeCoreAudioFormat
error:&assetError];
if (assetError) {
NSLog (@"error: %@", assetError);
return;
}
AudioChannelLayout channelLayout;
memset(&channelLayout, 0, sizeof(AudioChannelLayout));
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
[NSNumber numberWithFloat:44100.0], AVSampleRateKey,
[NSNumber numberWithInt:2], AVNumberOfChannelsKey,
[NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey,
[NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
[NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
[NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
[NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
nil];
AVAssetWriterInput *assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio
outputSettings:outputSettings];
if ([assetWriter canAddInput:assetWriterInput]) {
[assetWriter addInput:assetWriterInput];
} else {
NSLog (@"can't add asset writer input... die!");
return;
}
assetWriterInput.expectsMediaDataInRealTime = NO;
[assetWriter startWriting];
[assetReader startReading];
AVAssetTrack *soundTrack = [songAsset.tracks objectAtIndex:0];
CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale);
[assetWriter startSessionAtSourceTime: startTime];
__block UInt64 convertedByteCount = 0;
dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);
[assetWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue
usingBlock: ^
{
// NSLog (@"top of block");
while (assetWriterInput.readyForMoreMediaData) {
CMSampleBufferRef nextBuffer = [assetReaderOutput copyNextSampleBuffer];
if (nextBuffer) {
// append buffer
[assetWriterInput appendSampleBuffer: nextBuffer];
// NSLog (@"appended a buffer (%d bytes)",
// CMSampleBufferGetTotalSampleSize (nextBuffer));
convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
} else {
// done!
[assetWriterInput markAsFinished];
[assetWriter finishWriting];
[assetReader cancelReading];
NSDictionary *outputFileAttributes = [[NSFileManager defaultManager]
attributesOfItemAtPath:exportPath
error:nil];
//實(shí)現(xiàn)caf 轉(zhuǎn)mp3
[self audioCAFtoMP3:exportPath];
NSLog (@"done. file size is %lld",
[outputFileAttributes fileSize]);
break;
}
}
}];
}
2.caf >mp3
- (void)audioCAFtoMP3:(NSString *)wavPath {
NSString *cafFilePath = wavPath;
NSString *mp3FilePath = [NSString stringWithFormat:@"%@.mp3",[NSString stringWithFormat:@"%@",[cafFilePath substringToIndex:cafFilePath.length - 4]]];
@try {
int read, write;
FILE *pcm = fopen([cafFilePath cStringUsingEncoding:1], "rb"); //source 被轉(zhuǎn)換的音頻文件位置
fseek(pcm, 4*1024, SEEK_CUR); //skip file header
FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb"); //output 輸出生成的Mp3文件位置
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE*2];
unsigned char mp3_buffer[MP3_SIZE];
lame_t lame = lame_init();
lame_set_num_channels(lame,1);//設(shè)置1為單通道,默認(rèn)為2雙通道
lame_set_in_samplerate(lame, 44100.0);
lame_set_VBR(lame, vbr_default);
lame_set_brate(lame,8);
lame_set_mode(lame,3);
lame_set_quality(lame,2);
lame_init_params(lame);
do {
read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
if (read == 0)
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
else
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
lame_close(lame);
fclose(mp3);
fclose(pcm);
}
@catch (NSException *exception) {
NSLog(@"%@",[exception description]);
}
@finally {
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[UsingHUD hideInView:self.view];
//主線程上傳到oss
[self localdispose:mp3FilePath];
});
}
}
到此乐导,大功告成~~