5

opusをアプリケーションに統合しようとしています。エンコードおよびデコード関数は正の値を返しますが、これは成功を意味しますが、出力オーディオを再生できません。生のオーディオ データも再生できます。これがデータをエンコードする方法です。各パケットを分離するために 4 バイトのプレフィックスを使用します。

self.encoder = opus_encoder_create(24000, 1, OPUS_APPLICATION_VOIP, &opusError);
opus_encoder_ctl(self.encoder, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));



- (void) encodeBufferList:(AudioBufferList *)bufferList {
    BOOL success = TPCircularBufferProduceBytes(_circularBuffer, bufferList->mBuffers[0].mData, bufferList->mBuffers[0].mDataByteSize);
    if (!success) {
        NSLog(@"insufficient space in circular buffer!");
    }

    if (!_encoding) {
            _encoding = YES;

            dispatch_async(self.processingQueue, ^{
                [self startEncodingLoop];
            });
    }
}


-(void)startEncodingLoop
{
    int32_t availableBytes = 0;
    opus_int16 *data = (opus_int16*)TPCircularBufferTail(_circularBuffer, &availableBytes);
    int availableSamples = availableBytes / _inputASBD.mBytesPerFrame;

    /*!
     *  Use dynamic duration
     */
//    int validSamples[6] = {2.5, 5, 10, 20, 40, 60}; // in milisecond
//    int esample = validSamples[0] * self.sampleRate / 1000;
//    for (int i = 0; i < 6; i++) {
//        int32_t samp = validSamples[i] * self.sampleRate / 1000;
//        if (availableSamples < samp) {
//            break;
//        }
//        esample = samp;
//    }

    /*!
     *  Use 20ms
     */
    int esample = 20 * self.sampleRate / 1000;

    if (availableSamples < esample) {
        /*!
         *  Out of data. Finish encoding
         */
        self.encoding = NO;
        [self.eDelegate didFinishEncode];
        return;
    }

//    printf("raw input value for packet \n");
//    for (int i = 0; i < esample * self.numberOfChannels; i++) {
//        printf("%d :", data[i]);
//    }

    int returnValue = opus_encode(_encoder, data, esample, _encoderOutputBuffer, 1000);

    TPCircularBufferConsume(_circularBuffer, esample * sizeof(opus_int16) * self.numberOfChannels);

//    printf("output encode \n");
//    for (int i = 0; i < returnValue; i++) {
//        printf("%d :", _encoderOutputBuffer[i]);
//    }

    NSMutableData *outputData = [NSMutableData new];
    NSError *error = nil;
    if (returnValue <= 0) {
        error = [OKUtilities errorForOpusErrorCode:returnValue];
    }else {
        [outputData appendBytes:_encoderOutputBuffer length:returnValue * sizeof(unsigned char)];
        unsigned char int_field[4];
        int_to_char(returnValue , int_field);
        NSData *header = [NSData dataWithBytes:&int_field[0] length:4 * sizeof(unsigned char)];
        if (self.eDelegate) {
            [self.eDelegate didEncodeWithData:header];
        }
    }

    if (self.eDelegate) {
        [self.eDelegate didEncodeWithData:outputData];
    }

    [self startEncodingLoop];
}

そして、ここにデコード機能があります:

self.decoder = opus_decoder_create(24000, 1, &opusError);
opus_decoder_ctl(self.decoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
opus_decoder_ctl(self.decoder, OPUS_SET_GAIN(10));


-(void)startParseData:(unsigned char*)data remainingLen:(int)len
{
    if (len <= 0) {
        [self.dDelegate didFinishDecode];
        return;
    }
    int headLen = sizeof(unsigned char) * 4;
    unsigned char h[4];
    h[0] = data[0];
    h[1] = data[1];
    h[2] = data[2];
    h[3] = data[3];

    int packetLen = char_to_int(h);
    data += headLen;
    packetLen = packetLen * sizeof(unsigned char) * self.numberOfChannels;
    [self decodePacket:data length:packetLen remainingLen:len - headLen];
}

-(void)decodePacket:(unsigned char*)inputData length:(int)len remainingLen:(int)rl
{
    int bw = opus_packet_get_bandwidth(inputData); //TEST: return OPUS_BANDWIDTH_SUPERWIDEBAND here
    int32_t decodedSamples = 0;

//    int validSamples[6] = {2.5, 5, 10, 20, 40, 60}; // in milisecond
    /*!
     *  Use 60ms
     */
    int esample = 60 * self.sampleRate / 1000;
//    printf("input decode \n");
//    for (int i = 0; i < len; i++) {
//        printf("%d :", inputData[i]);
//    }

    _decoderBufferLength = esample * self.numberOfChannels * sizeof(opus_int16);
    int returnValue = opus_decode(_decoder, inputData, len, _outputBuffer, esample, 1);
    if (returnValue < 0) {
        NSError *error = [OKUtilities errorForOpusErrorCode:returnValue];
        NSLog(@"decode error %@", error);
        inputData += len;
        [self startParseData:inputData remainingLen:rl - len];
        return;
    }
    decodedSamples = returnValue;

    NSUInteger length = decodedSamples * self.numberOfChannels;

//    printf("raw decoded data \n");
//    for (int i = 0; i < length; i++) {
//        printf("%d :", _outputBuffer[i]);
//    }

    NSData *audioData = [NSData dataWithBytes:_outputBuffer length:length * sizeof(opus_int16)];
    if (self.dDelegate) {
        [self.dDelegate didDecodeData:audioData];
    }
    inputData += len;
    [self startParseData:inputData remainingLen:rl - len];
}

私が欠けているものを指摘するのを手伝ってください。例は素晴らしいでしょう。

4

3 に答える 3

5

問題はデコード側にあると思います:

  • に引数1として渡します。これにより、現在のパケットのエラー訂正データから、パケット全体の期間に相当するデータを生成するようにデコーダーに要求します。あなたのコードには失われたパケット追跡が見られないので、代わりに渡す必要があります。その変更により、入力と出力の期間が一致するはずです。fecopus_decode()0

  • モノラル出力用にデコーダーを構成しますが、後でself.numberOfChannels長さの計算に使用します。それらは一致する必要があります。そうしないと、予期しない動作が発生する可能性があります。

  • OPUS_SET_SIGNALopus_decoder_ctl() では何もしませんが、動作に影響を与えずに OPUS_UNIMPLEMENTED を返すだけです。

  • Opus パケットの持続時間は最大 120 ミリ秒であるため、60 ミリ秒の制限では一部のストリームのデコードに失敗する可能性があります。libopus はデフォルトで 20 ミリ秒のフレームに設定されているため、設定した方法で問題を引き起こさない独自のアプリとのみ通信している場合。

于 2015-05-29T18:19:32.363 に答える
3

私は問題が何であるかを見つけました。オーディオ形式を float に設定しましたkAudioFormatFlagIsPacked|kAudioFormatFlagIsFloat;。の代わりにopus_encode_floatandを使用する必要があります。@Ralph が言うように、= 0 inを使用する必要があります。@ラルフに感謝します。opus_decode_floatopus_encode opus_decodefecopus_decode

于 2015-06-01T02:46:47.753 に答える