2012-05-05 1 views
1

Итак, я пытаюсь сделать простой расчет по ранее записанному аудио (из AVAsset), чтобы создать визуальную форму волны. В настоящее время я делаю это путем усреднения набора выборок, размер которых определяется делением размера аудиофайла на разрешение, которое требуется для формы волны.Установка временного диапазона в AVAssetReader вызывает замораживание

Все это прекрасно работает, за исключением одной проблемы ... это слишком медленно. Запуск на 3GS, обработка аудиофайла занимает около 3% времени, необходимого для его воспроизведения, что является способом замедления (например, 1-часовой аудиофайл занимает около 2,5 минут для обработки). Я попытался максимально оптимизировать метод, но он не работает. Я отправлю код, который я использую для обработки файла. Может быть, кто-то сможет с этим справиться, но то, что я действительно ищу, - это способ обработки файла без необходимости перебирать каждый байт. Итак, скажем, учитывая разрешение 2000, я хочу получить доступ к файлу и взять образец на каждую из 2000 пунктов. Я думаю, что это будет намного быстрее, особенно если файл больше. Но единственный способ узнать исходные данные - получить доступ к аудиофайлу линейным способом. Есть идеи? Вот код, который я использую для обработки файла (обратите внимание, что все классовые классы начинаются с «_»):

Так что я полностью изменил этот вопрос. Я с опозданием понял, что AVAssetReader имеет свойство 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 
)} 

Я использую время профилировщика на приложение и да, он просто сидит там с минимальным количеством обработки. Не могу понять, что происходит. Важно отметить, что это не происходит, если я не устанавливаю свойство timeRange для AVAssetReader. Я проверил, и значения для 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

Я, наконец, понял почему. По-видимому, существует некоторая «минимальная» продолжительность, которую вы можете указать для timeRange AVAssetReader. Я не уверен, что именно этот минимум, где-то выше 1000, но менее 5000. Возможно, что минимальные изменения с продолжительностью актива ... честно говоря, я не уверен. Вместо этого я сохранил продолжительность (которая бесконечна) и изменила время начала. Вместо обработки всего образца я копирую только один буферный блок, обрабатывая его, а затем ищем в следующий раз. У меня все еще есть проблемы с кодом, но я отправлю это как еще один вопрос, если не могу понять.

 Смежные вопросы

  • Нет связанных вопросов^_^