0

アプリのベースとしてkxmovie (ffmpeg ベースのビデオ プレーヤー) を使用しています。デバイスに接続されているのがヘッドフォンだけである場合に、iOS で RemoteI/O ユニットがどのように機能するかを理解しようとしています。 2 つ以上のチャネル (たとえば、サラウンド 6 トラック チャネル) を持つトラックを再生します。出力チャンネルの設定で動いているようで、バッファは2チャンネルしかありません。これは Core Audio のプル構造のせいでしょうか。もしそうなら、トラックの他のチャンネルはどうなっていますか? それらはダウンミックスされていますか、それとも単に無視されていますか?

remoteio ユニットに接続されたレンダリング コールバックのコードは次のとおりです。

- (BOOL) renderFrames: (UInt32) numFrames
               ioData: (AudioBufferList *) ioData
{
    NSLog(@"Number of channels in buffer: %lu",ioData->mNumberBuffers);

    for (int iBuffer=0; iBuffer < ioData->mNumberBuffers; ++iBuffer) {
        memset(ioData->mBuffers[iBuffer].mData, 0, ioData->mBuffers[iBuffer].mDataByteSize);
    }


    if (_playing && _outputBlock ) {

        // Collect data to render from the callbacks
        _outputBlock(_outData, numFrames, _numOutputChannels);

        // Put the rendered data into the output buffer
        if (_numBytesPerSample == 4) // then we've already got floats
        {
            float zero = 0.0;

            for (int iBuffer=0; iBuffer < ioData->mNumberBuffers; ++iBuffer) {

                int thisNumChannels = ioData->mBuffers[iBuffer].mNumberChannels;

                for (int iChannel = 0; iChannel < thisNumChannels; ++iChannel) {
                    vDSP_vsadd(_outData+iChannel, _numOutputChannels, &zero, (float *)ioData->mBuffers[iBuffer].mData, thisNumChannels, numFrames);
                }
            }
        }
        else if (_numBytesPerSample == 2) // then we need to convert SInt16 -> Float (and also scale)
        {
            float scale = (float)INT16_MAX;
            vDSP_vsmul(_outData, 1, &scale, _outData, 1, numFrames*_numOutputChannels);

            for (int iBuffer=0; iBuffer < ioData->mNumberBuffers; ++iBuffer) {

                int thisNumChannels = ioData->mBuffers[iBuffer].mNumberChannels;

                for (int iChannel = 0; iChannel < thisNumChannels; ++iChannel) {
                    vDSP_vfix16(_outData+iChannel, _numOutputChannels, (SInt16 *)ioData->mBuffers[iBuffer].mData+iChannel, thisNumChannels, numFrames);
                }
            }

        }        
    }

    return noErr;
}

ありがとう!

編集: ASBD (_oputFormat) のコードは次のとおりです。リモートから値を直接取得しています。また、メソッド ファイル全体をここで確認することもできます。

if (checkError(AudioUnitGetProperty(_audioUnit,
                                    kAudioUnitProperty_StreamFormat,
                                    kAudioUnitScope_Input,
                                    0,
                                    &_outputFormat,
                                    &size),
               "Couldn't get the hardware output stream format"))
    return NO;


_outputFormat.mSampleRate = _samplingRate;
if (checkError(AudioUnitSetProperty(_audioUnit,
                                    kAudioUnitProperty_StreamFormat,
                                    kAudioUnitScope_Input,
                                    0,
                                    &_outputFormat,
                                    size),
               "Couldn't set the hardware output stream format")) {

    // just warning
}

_numBytesPerSample = _outputFormat.mBitsPerChannel / 8;
_numOutputChannels = _outputFormat.mChannelsPerFrame;

NSLog(@"Current output bytes per sample: %ld", _numBytesPerSample);
NSLog(@"Current output num channels: %ld", _numOutputChannels);

// Slap a render callback on the unit
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = renderCallback;
callbackStruct.inputProcRefCon = (__bridge void *)(self);

if (checkError(AudioUnitSetProperty(_audioUnit,
                                    kAudioUnitProperty_SetRenderCallback,
                                    kAudioUnitScope_Input,
                                    0,
                                    &callbackStruct,
                                    sizeof(callbackStruct)),
               "Couldn't set the render callback on the audio unit"))
    return NO;
4

1 に答える 1

0

チャンネルをステレオにリミックスするコードをようやく見つけました。RIO の ASBD を使用して、KxAudioManager にプロパティを設定します。次に、KxMovieDecoder.m で、同じ変数を使用して ffmpeg オプションを設定します。コードは次のとおりです。

id<KxAudioManager> audioManager = [KxAudioManager audioManager];
swrContext = swr_alloc_set_opts(NULL,
                                av_get_default_channel_layout(audioManager.numOutputChannels),
                                AV_SAMPLE_FMT_S16,
                                audioManager.samplingRate,
                                av_get_default_channel_layout(codecCtx->channels),
                                codecCtx->sample_fmt,
                                codecCtx->sample_rate,
                                0,
                                NULL);

それでは、ffmpeg がどのようにデコードを行っているかを読んでみましょう。楽しい時間。

于 2013-11-25T21:33:53.187 に答える