【问题标题】:AVAssetReader to AudioQueueBufferAVAssetReader 到 AudioQueueBuffer
【发布时间】:2012-07-09 02:01:33
【问题描述】:

目前,我正在做一个小测试项目,看看是否可以从 AVAssetReader 获取样本,以便在 iOS 上使用 AudioQueue 进行播放。

我读过这个: (Play raw uncompressed sound with AudioQueue, no sound) 还有这个:(How to correctly read decoded PCM samples on iOS using AVAssetReader -- currently incorrect decoding),

这两者实际上都有帮助。在阅读之前,我完全没有声音。现在,我得到了声音,但音频播放速度非常快。这是我第一次涉足音频编程,非常感谢任何帮助。

我这样初始化阅读器:

NSDictionary * outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                         [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
                                         [NSNumber numberWithFloat:44100.0], AVSampleRateKey,
                                         [NSNumber numberWithInt:2], AVNumberOfChannelsKey,
                                         [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
                                         [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
                                         [NSNumber numberWithBool:NO], AVLinearPCMIsFloatKey,
                                         [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,

                                         nil];

        output = [[AVAssetReaderAudioMixOutput alloc] initWithAudioTracks:uasset.tracks audioSettings:outputSettings];
        [reader addOutput:output];
...

我就这样抓取了数据:

CMSampleBufferRef ref= [output copyNextSampleBuffer];
    // NSLog(@"%@",ref);
    if(ref==NULL)
        return;
    //copy data to file
    //read next one
    AudioBufferList audioBufferList;
    NSMutableData *data = [NSMutableData data];
    CMBlockBufferRef blockBuffer;
    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(ref, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer);
    // NSLog(@"%@",blockBuffer);

    if(blockBuffer==NULL)
    {
        [data release];
        return;
    }
    if(&audioBufferList==NULL)
    {
        [data release];
        return;
    }

    //stash data in same object
    for( int y=0; y<audioBufferList.mNumberBuffers; y++ )
    {
//        NSData* throwData;
        AudioBuffer audioBuffer = audioBufferList.mBuffers[y];
        [self.delegate streamer:self didGetAudioBuffer:audioBuffer];
        /*
        Float32 *frame = (Float32*)audioBuffer.mData;
        throwData = [NSData dataWithBytes:audioBuffer.mData length:audioBuffer.mDataByteSize];
        [self.delegate streamer:self didGetAudioBuffer:throwData];
        [data appendBytes:audioBuffer.mData length:audioBuffer.mDataByteSize];
         */
    }

最终将我们带到音频队列,以这种方式设置:

//Apple's own code for canonical PCM
    audioDesc.mSampleRate       = 44100.0;
    audioDesc.mFormatID         = kAudioFormatLinearPCM;
    audioDesc.mFormatFlags      = kAudioFormatFlagsAudioUnitCanonical;
    audioDesc.mBytesPerPacket   = 2 * sizeof (AudioUnitSampleType);    // 8
    audioDesc.mFramesPerPacket  = 1;
    audioDesc.mBytesPerFrame    = 1 * sizeof (AudioUnitSampleType);    // 8
    audioDesc.mChannelsPerFrame = 2;
    audioDesc.mBitsPerChannel   = 8 * sizeof (AudioUnitSampleType);    // 32


err = AudioQueueNewOutput(&audioDesc, handler_OSStreamingAudio_queueOutput, self, NULL, NULL, 0, &audioQueue);
    if(err){
#pragma warning  handle error
//never errs, am using breakpoint to check
        return;
    }

我们就这样排队

while (inNumberBytes)
        {
            size_t bufSpaceRemaining = kAQDefaultBufSize - bytesFilled;
            if (bufSpaceRemaining < inNumberBytes)
            {
                AudioQueueBufferRef fillBuf = audioQueueBuffer[fillBufferIndex];
        fillBuf->mAudioDataByteSize = bytesFilled;
        err = AudioQueueEnqueueBuffer(audioQueue, fillBuf, 0, NULL);
            }


                bufSpaceRemaining = kAQDefaultBufSize - bytesFilled;
                size_t copySize;
                if (bufSpaceRemaining < inNumberBytes)
                {
                    copySize = bufSpaceRemaining;
                }
                else
                {
                    copySize = inNumberBytes;
                }

                if (bytesFilled > packetBufferSize)
                {
                    return;
                }

                AudioQueueBufferRef fillBuf = audioQueueBuffer[fillBufferIndex];
                memcpy((char*)fillBuf->mAudioData + bytesFilled, (const char*)(inInputData + offset), copySize);


                bytesFilled += copySize;
                packetsFilled = 0;
                inNumberBytes -= copySize;
                offset += copySize;
            }
        }

我试图尽可能地包含代码,以便让每个人都能轻松指出我在哪里是个白痴。话虽如此,我感觉我的问题出现在轨道阅读器的输出设置声明中或 AudioQueue 的实际声明中(我向队列描述我将发送什么样的音频)。事实是,我真的不知道如何在数学上实际生成这些数字(每个数据包的字节数,每个数据包的帧数,你有什么)。对此的解释将不胜感激,并提前感谢您的帮助。

【问题讨论】:

    标签: objective-c ios core-audio audioqueueservices avassetreader


    【解决方案1】:

    出于某种原因,即使我看到的每个使用 LPCM 的音频队列示例都有

    ASBD.mBitsPerChannel = 8* sizeof (AudioUnitSampleType);
    

    对我来说,事实证明我需要

    ASBD.mBitsPerChannel    = 2*bytesPerSample;
    

    关于以下内容的描述:

    ASBD.mFormatID          = kAudioFormatLinearPCM;
    ASBD.mFormatFlags       = kAudioFormatFlagsAudioUnitCanonical;
    ASBD.mBytesPerPacket    = bytesPerSample;
    ASBD.mBytesPerFrame     = bytesPerSample;
    ASBD.mFramesPerPacket   = 1;
    ASBD.mBitsPerChannel    = 2*bytesPerSample;
    ASBD.mChannelsPerFrame  = 2;           
    ASBD.mSampleRate        = 48000;
    

    我不知道为什么会这样,这让我很困扰……但希望我最终能弄清楚。

    如果有人能向我解释为什么会这样,我将非常感激。

    【讨论】:

    • 我很好奇你为什么将采样率指定为 48000 .. 你从哪里得到这个数字?我也玩过我的代码中的格式..它的输入和输出几乎都是lPCM格式..但我只是听到噪音..你能在下面的问题中看看我的代码,看看有没有什么问题向上? stackoverflow.com/questions/12264799/…
    • 我想我使用了 48000,因为我看到了一个使用它的示例。当时我有点在黑暗中刺伤。我会看看你的问题,看看我们能不能找到什么。
    【解决方案2】:

    不确定这是多少答案,但会有太多的文字和链接来发表评论,希望它会有所帮助(也许会引导你找到答案)。

    首先,我知道在我当前的项目中调整采样率会影响声音的速度,因此您可以尝试使用这些设置。但是 44k 是我在大多数默认实现中看到的,包括苹果示例 SpeakHere。但是,我会花一些时间将您的代码与该示例进行比较,因为存在很多差异。就像入队前检查一样。

    首先查看此帖子https://stackoverflow.com/a/4299665/530933 它讨论了您需要如何了解音频格式,特别是一帧中有多少字节,以及适当的投射

    也祝你好运。我在这里发布了很多问题,苹果论坛和 ios 论坛(不是官方论坛)。很少有回应/帮助。为了获得今天的成就(ulaw 中的音频录制和流式传输),我最终不得不打开 Apple Dev Support Ticket。在处理音频之前我从来不知道存在(开发支持)。一件好事是,如果您有一个有效的开发帐户,您将免费获得 2 次事件! CoreAudio 不好玩。文档很少,除了 SpeakHere 之外没有太多示例。我确实发现的一件事是框架头文件确实有一些很好的信息和this book。不幸的是,我才刚刚开始阅读这本书,否则我可能会为您提供进一步的帮助。

    您还可以查看我自己的一些帖子,这些帖子我已尽力回答。 This is my main audio question which I have spent alot of time on to compile all pertinent links and code.

    using AQRecorder (audioqueue recorder example) in an objective c class

    trying to use AVAssetWriter for ulaw audio (2)

    【讨论】:

    • 感谢您的洞察力。它没有准确回答问题,但帮助我找到了解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 2012-06-20
    • 1970-01-01
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多