2012-05-05 8 views
1

これで、波形のビジュアルを作成するために、以前に録音したオーディオ(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; 
} 

答えて

1

私はついになぜそれを理解しましたか? AVAssetReaderのtimeRangeに指定できる最小限の期間があるようです。私はその最低限が何であるかは分かりません.1000以上5,000未満です。それは、資産の期間との最小限の変更可能性があります...正直なところ私は分かりません。代わりに、私は持続時間(無限大)を同じに保ち、単に開始時間を変更しました。サンプル全体を処理する代わりに、私は1つのバッファブロックだけをコピーし、それを処理して次回に探します。私はまだコードに問題がありますが、私はそれを把握できない場合は別の質問として投稿します。

関連する問題