Ios Avassetrader以低质量播放MPMediaItem?
在结合了几个问题的答案后,我成功地使用Avassetrader从MPMediaItem中获取了原始数据,如和和一个nice。我也可以使用FMOD播放这些原始数据,但随后出现了一个问题 结果音频的质量似乎低于原始曲目。虽然AVAssetTrack formatDescription告诉我数据中有两个通道,但结果听起来是单声道的。它听起来也有点低沉(不那么脆),好像比特率降低了 是我做错了什么,还是Avassetrader故意降低了MPMediaItem数据的质量(因为盗版)Ios Avassetrader以低质量播放MPMediaItem?,ios,audio,avfoundation,fmod,Ios,Audio,Avfoundation,Fmod,在结合了几个问题的答案后,我成功地使用Avassetrader从MPMediaItem中获取了原始数据,如和和一个nice。我也可以使用FMOD播放这些原始数据,但随后出现了一个问题 结果音频的质量似乎低于原始曲目。虽然AVAssetTrack formatDescription告诉我数据中有两个通道,但结果听起来是单声道的。它听起来也有点低沉(不那么脆),好像比特率降低了 是我做错了什么,还是Avassetrader故意降低了MPMediaItem数据的质量(因为盗版) 初始化AvasseT
初始化AvasseTrader和AvasseTraderTrackOutput
//准备AVAsset和AVAssetReaderOutput等
MPMediaItem*mediaItem=。。。;
NSURL*ipodAudioUrl=[mediaItem valueForProperty:MPMediaItemPropertyAsetUrl];
AVURLAsset*asset=[[AVURLAsset alloc]initWithURL:ipodAudioUrl选项:nil];
n错误*错误=nil;
AssetTreader=[[AvAssetTreader alloc]initWithAsset:资产错误:&错误];
如果(错误)
NSLog(@“创建读取器时出错:%@,[error debugDescription]);
AVAssetTrack*songTrack=[asset.tracks对象索引:0];
NSArray*trackDescriptions=songTrack.formatDescriptions;
numChannels=2;
for(无符号整数i=0;i<[trackDescriptions计数];+i)
{
cAudioFormatDescriptionRef项=(cAudioFormatDescriptionRef)[trackDescriptions对象索引:i];
const AudioStreamBasicDescription*bobTheDesc=cAudioFormatDescription GetStreamBasicDescription(项目);
if(bobTheDesc&&bobTheDesc->mChannelsPerFrame==1){
numChannels=1;
}
}
NSDictionary*outputSettingsDict=[[[NSDictionary alloc]initWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatLinearPCM],AVFormatIDKey,
[NSNumber numberWithInt:OUTPUTRATE],AVSampleRateKey,
[NSNumber NUMBER WITHIT:16],AVLINEARPCMBITDEPTHEY,
[NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey,
[NSNumber numberWithBool:NO]、AVLinearPCMIsFloatKey、,
[NSNumber numberWithBool:NO],AVLINEARPCM为非交叉,
无]自动释放];
AvassetraderTrackOutput*输出=[[AvassetraderTrackOutput alloc]initWithTrack:songTrack输出设置:输出设置ICT]自动释放];
[AssetTreader添加输出:输出];
[assetReader startReading];
初始化FMOD和FMOD声音
//初始化FMOD
FMOD_结果结果=FMOD_正常;
无符号整数版本=0;
/*
创建系统对象并初始化
*/
结果=FMOD::系统\创建(和系统);
错误检查(结果);
结果=系统->获取版本(&V);
错误检查(结果);
if(版本设置软件格式(输出、FMOD声音格式、PCM16、1、0、FMOD、DSP、重采样、线性);
错误检查(结果);
结果=系统->初始化(32,FMOD_init_NORMAL | FMOD_init_ENABLE_PROFILE,NULL);
错误检查(结果);
//初始FMOD声流
CMTimeRange timeRange=[songTrack timeRange];
浮动持续时间秒=timeRange.duration.value/timeRange.duration.timescale;
FMOD_CREATESOUNDEXINFO exinfo={0};
memset(&exinfo,0,sizeof(FMOD_CREATESOUNDEXINFO));
exinfo.cbsize=sizeof(FMOD_CREATESOUNDEXINFO);/*必需的*/
exinfo.decodebuffersize=输出;/*样本中流更新的块大小。这将是传递给用户回调的数据量*/
exinfo.length=输出*numChannels*sizeof(有符号短)*持续时间秒;/*PCM数据的长度,以整首歌曲的字节为单位(对于Sound::getLength)*/
exinfo.numchannels=numchannels;/*声音中的频道数*/
exinfo.defaultfrequency=输出;/*声音的默认播放速率*/
exinfo.format=FMOD\u SOUND\u format\u PCM16;/*声音的数据格式*/
exinfo.pcmreadcallback=pcmreadcallback;/*用于读取的用户回调*/
exinfo.pcmsetposcallback=pcmsetposcallback;/*用于查找的用户回调*/
结果=系统->创建流(NULL、FMOD\u OPENUSER、&exinfo、&sound);
错误检查(结果);
结果=系统->播放声音(FMOD_通道自由、声音、错误和通道);
错误检查(结果);
从AvasseTraderTrack输出读取到环形缓冲区
AvassetraderTrackOutput*trackOutput=(AvassetraderTrackOutput*)[AssetTreader.outputs对象索引:0];
CMSampleBufferRef sampleBufferRef=[trackOutput copyNextSampleBuffer];
if(sampleBufferRef)
{
AudioBufferList AudioBufferList;
CMBlockBufferRef块缓冲区;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBufferRef、NULL和audioBufferList、sizeof(audioBufferList)、NULL、NULL、0和blockBuffer);
if(blockBuffer==NULL)
{
停止加载=是;
继续;
}
如果(&audioBufferList==NULL)
{
停止加载=是;
继续;
}
if(audioBufferList.mNumberBuffers!=1)
NSLog(@“numBuffers=%lu”,audioBufferList.mNumberBuffers);
对于(int y=0;y我不熟悉FMOD,所以我不能在那里发表评论。Avassetrader不做任何“复制保护”的事情,所以这不成问题。(如果你能获得AVAssetURL,这首歌是无DRM的)
因为您使用的是非交错缓冲区,所以只有一个缓冲区,所以我猜您的最后一位代码可能是错误的
这是一些代码对我来说很好的例子。BTW,for for循环可能不会很有性能。你可以考虑使用<代码> MeMCPY <代码>……
如果您不受现有环形缓冲区的限制,
#define OUTPUTRATE 44100
// prepare AVAsset and AVAssetReaderOutput etc
MPMediaItem* mediaItem = ...;
NSURL* ipodAudioUrl = [mediaItem valueForProperty:MPMediaItemPropertyAssetURL];
AVURLAsset * asset = [[AVURLAsset alloc] initWithURL:ipodAudioUrl options:nil];
NSError * error = nil;
assetReader = [[AVAssetReader alloc] initWithAsset:asset error:&error];
if(error)
NSLog(@"error creating reader: %@", [error debugDescription]);
AVAssetTrack* songTrack = [asset.tracks objectAtIndex:0];
NSArray* trackDescriptions = songTrack.formatDescriptions;
numChannels = 2;
for(unsigned int i = 0; i < [trackDescriptions count]; ++i)
{
CMAudioFormatDescriptionRef item = (CMAudioFormatDescriptionRef)[trackDescriptions objectAtIndex:i];
const AudioStreamBasicDescription* bobTheDesc = CMAudioFormatDescriptionGetStreamBasicDescription (item);
if(bobTheDesc && bobTheDesc->mChannelsPerFrame == 1) {
numChannels = 1;
}
}
NSDictionary* outputSettingsDict = [[[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatLinearPCM],AVFormatIDKey,
[NSNumber numberWithInt:OUTPUTRATE],AVSampleRateKey,
[NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,
[NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey,
[NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
[NSNumber numberWithBool:NO],AVLinearPCMIsNonInterleaved,
nil] autorelease];
AVAssetReaderTrackOutput * output = [[[AVAssetReaderTrackOutput alloc] initWithTrack:songTrack outputSettings:outputSettingsDict] autorelease];
[assetReader addOutput:output];
[assetReader startReading];
// Init FMOD
FMOD_RESULT result = FMOD_OK;
unsigned int version = 0;
/*
Create a System object and initialize
*/
result = FMOD::System_Create(&system);
ERRCHECK(result);
result = system->getVersion(&version);
ERRCHECK(result);
if (version < FMOD_VERSION)
{
fprintf(stderr, "You are using an old version of FMOD %08x. This program requires %08x\n", version, FMOD_VERSION);
exit(-1);
}
result = system->setSoftwareFormat(OUTPUTRATE, FMOD_SOUND_FORMAT_PCM16, 1, 0, FMOD_DSP_RESAMPLER_LINEAR);
ERRCHECK(result);
result = system->init(32, FMOD_INIT_NORMAL | FMOD_INIT_ENABLE_PROFILE, NULL);
ERRCHECK(result);
// Init FMOD sound stream
CMTimeRange timeRange = [songTrack timeRange];
float durationInSeconds = timeRange.duration.value / timeRange.duration.timescale;
FMOD_CREATESOUNDEXINFO exinfo = {0};
memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); /* required. */
exinfo.decodebuffersize = OUTPUTRATE; /* Chunk size of stream update in samples. This will be the amount of data passed to the user callback. */
exinfo.length = OUTPUTRATE * numChannels * sizeof(signed short) * durationInSeconds; /* Length of PCM data in bytes of whole song (for Sound::getLength) */
exinfo.numchannels = numChannels; /* Number of channels in the sound. */
exinfo.defaultfrequency = OUTPUTRATE; /* Default playback rate of sound. */
exinfo.format = FMOD_SOUND_FORMAT_PCM16; /* Data format of sound. */
exinfo.pcmreadcallback = pcmreadcallback; /* User callback for reading. */
exinfo.pcmsetposcallback = pcmsetposcallback; /* User callback for seeking. */
result = system->createStream(NULL, FMOD_OPENUSER, &exinfo, &sound);
ERRCHECK(result);
result = system->playSound(FMOD_CHANNEL_FREE, sound, false, &channel);
ERRCHECK(result);
AVAssetReaderTrackOutput * trackOutput = (AVAssetReaderTrackOutput *)[assetReader.outputs objectAtIndex:0];
CMSampleBufferRef sampleBufferRef = [trackOutput copyNextSampleBuffer];
if (sampleBufferRef)
{
AudioBufferList audioBufferList;
CMBlockBufferRef blockBuffer;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBufferRef, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer);
if(blockBuffer == NULL)
{
stopLoading = YES;
continue;
}
if(&audioBufferList == NULL)
{
stopLoading = YES;
continue;
}
if(audioBufferList.mNumberBuffers != 1)
NSLog(@"numBuffers = %lu", audioBufferList.mNumberBuffers);
for( int y=0; y<audioBufferList.mNumberBuffers; y++ )
{
AudioBuffer audioBuffer = audioBufferList.mBuffers[y];
SInt8 *frame = (SInt8*)audioBuffer.mData;
for(int i=0; i<audioBufferList.mBuffers[y].mDataByteSize; i++)
{
ringBuffer->push_back(frame[i]);
}
}
CMSampleBufferInvalidate(sampleBufferRef);
CFRelease(sampleBufferRef);
}
CMSampleBufferRef nextBuffer = NULL;
if(_reader.status == AVAssetReaderStatusReading)
{
nextBuffer = [_readerOutput copyNextSampleBuffer];
}
if (nextBuffer)
{
AudioBufferList abl;
CMBlockBufferRef blockBuffer;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
nextBuffer,
NULL,
&abl,
sizeof(abl),
NULL,
NULL,
kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
&blockBuffer);
// the correct way to get the number of bytes in the buffer
size_t size = CMSampleBufferGetTotalSampleSize(nextBuffer);
memcpy(ringBufferTail, abl.mBuffers[0].mData, size);
CFRelease(nextBuffer);
CFRelease(blockBuffer);
}
result = system->setSoftwareFormat(OUTPUTRATE, FMOD_SOUND_FORMAT_PCM16, 2, 0, FMOD_DSP_RESAMPLER_LINEAR);