これで、波形のビジュアルを作成するために、以前に録音したオーディオ(AVAssetから)を簡単に計算しようとしています。私は現在、サンプルのセットを平均することによってこれを行います。そのサイズは、オーディオファイルのサイズを波形のために必要な解像度で割ることによって決定されます。AVAssetReaderの時間範囲を設定するとフリーズする
これはすべて問題なく1つの問題を除いて問題なく動作します。遅すぎます。 3GS上で実行すると、オーディオファイルを処理するのにかかる時間の約3%がかかるため、処理速度が遅くなります(たとえば、1時間のオーディオファイルは処理に約2.5分かかります)。私はできるだけメソッドを最適化しようとしましたが、機能しません。ファイルを処理するために使用するコードを投稿します。誰かがそれを手伝うことができるかもしれませんが、私が本当に求めているのは、ファイルを1バイトごとに処理することなく処理する方法です。だから、2000の解像度でファイルにアクセスし、2000ポイントごとにサンプルを取ってみたいとします。私はこれがはるかに速くなると思う、特にファイルが大きい場合。しかし、私が生データを得るために知っている唯一の方法は、オーディオファイルに線形にアクセスすることです。何か案は?ファイルを処理するコードは次のとおりです(すべてのクラス行は '_'で始まります)。
この質問を完全に変更しました。私は後天的にAVAssetReaderは、 "seeking"のために使用されているtimeRangeプロパティを持っていることに気付きました。これはまさに私が探していたものです(上記のオリジナルの質問を参照)。さらに、質問は尋ねられて答えられました(私はこれまでにそれを見つけられませんでした)、私は質問を複製したくありません。しかし、私はまだ問題があります。私のアプリはしばらくフリーズしてしまい、いつでも私はcopyNextSampleBuffer
を試してみるとクラッシュします。私は何が起こっているのか分からない。私はどのような種類の再帰ループでもないように見えますが、関数呼び出しからは決して戻りません。ログをチェックすると、私は、このエラーを与える示しています
Exception Type: 00000020
Exception Codes: 0x8badf00d
Highlighted Thread: 0
Application Specific Information:
App[10570] has active assertions beyond permitted time:
{(
<SBProcessAssertion: 0xddd9300> identifier: Suspending process: App[10570] permittedBackgroundDuration: 10.000000 reason: suspend owner pid:52 preventSuspend preventThrottleDownCPU preventThrottleDownUI
)}
私はアプリの時間プロファイラを使用し、うん、それだけで処理最小限の量とそこに座っています。何が起こっているのか分かりません。 AVAssetReaderのtimeRangeプロパティを設定しないと、これは発生しないことに注意することが重要です。私はチェックしてtimeRangeの値は有効ですが、それを設定するのは何らかの理由で問題を引き起こしています。私の処理コードは次のとおりです。
- (void) processSampleData{
if (!_asset || CMTimeGetSeconds(_asset.duration) <= 0) return;
NSError *error = nil;
AVAssetTrack *songTrack = _asset.tracks.firstObject;
if (!songTrack) return;
NSDictionary *outputSettingsDict = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatLinearPCM],AVFormatIDKey,
[NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
[NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey,
[NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
[NSNumber numberWithBool:NO],AVLinearPCMIsNonInterleaved,
nil];
UInt32 sampleRate = 44100.0;
_channelCount = 1;
NSArray *formatDesc = songTrack.formatDescriptions;
for(unsigned int i = 0; i < [formatDesc count]; ++i) {
CMAudioFormatDescriptionRef item = (__bridge_retained CMAudioFormatDescriptionRef)[formatDesc objectAtIndex:i];
const AudioStreamBasicDescription* fmtDesc = CMAudioFormatDescriptionGetStreamBasicDescription (item);
if(fmtDesc) {
sampleRate = fmtDesc->mSampleRate;
_channelCount = fmtDesc->mChannelsPerFrame;
}
CFRelease(item);
}
UInt32 bytesPerSample = 2 * _channelCount; //Bytes are hard coded by AVLinearPCMBitDepthKey
_normalizedMax = 0;
_sampledData = [[NSMutableData alloc] init];
SInt16 *channels[_channelCount];
char *sampleRef;
SInt16 *samples;
NSInteger sampleTally = 0;
SInt16 cTotal;
_sampleCount = DefaultSampleSize * [UIScreen mainScreen].scale;
NSTimeInterval intervalBetweenSamples = _asset.duration.value/_sampleCount;
NSTimeInterval sampleSize = fmax(100, intervalBetweenSamples/_sampleCount);
double assetTimeScale = _asset.duration.timescale;
CMTimeRange timeRange = CMTimeRangeMake(CMTimeMake(0, assetTimeScale), CMTimeMake(sampleSize, assetTimeScale));
SInt16 totals[_channelCount];
@autoreleasepool {
for (int i = 0; i < _sampleCount; i++) {
AVAssetReader *reader = [AVAssetReader assetReaderWithAsset:_asset error:&error];
AVAssetReaderTrackOutput *trackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:songTrack outputSettings:outputSettingsDict];
[reader addOutput:trackOutput];
reader.timeRange = timeRange;
[reader startReading];
while (reader.status == AVAssetReaderStatusReading) {
CMSampleBufferRef sampleBufferRef = [trackOutput copyNextSampleBuffer];
if (sampleBufferRef){
CMBlockBufferRef blockBufferRef = CMSampleBufferGetDataBuffer(sampleBufferRef);
size_t length = CMBlockBufferGetDataLength(blockBufferRef);
int sampleCount = length/bytesPerSample;
for (int i = 0; i < sampleCount ; i += _channelCount) {
CMBlockBufferAccessDataBytes(blockBufferRef, i * bytesPerSample, _channelCount, channels, &sampleRef);
samples = (SInt16 *)sampleRef;
for (int channel = 0; channel < _channelCount; channel++)
totals[channel] += samples[channel];
sampleTally++;
}
CMSampleBufferInvalidate(sampleBufferRef);
CFRelease(sampleBufferRef);
}
}
for (int i = 0; i < _channelCount; i++){
cTotal = abs(totals[i]/sampleTally);
if (cTotal > _normalizedMax) _normalizedMax = cTotal;
[_sampledData appendBytes:&cTotal length:sizeof(cTotal)];
totals[i] = 0;
}
sampleTally = 0;
timeRange.start = CMTimeMake((intervalBetweenSamples * (i + 1)) - sampleSize, assetTimeScale); //Take the sample just before the interval
}
}
_assetNeedsProcessing = NO;
}