0

私のアプリでは、デバイスのデフォルトのマイクからサウンドを録音し、RTSP サーバーに送信してさらにストリーミングする必要があります。

私のレコーダーの状態構造は次のとおりです。

typedef struct AQRecorderState {
    AudioStreamBasicDescription  mDataFormat;                   // 2
    AudioQueueRef                mQueue;                        // 3
    AudioQueueBufferRef          mBuffers[kNumberRecordBuffers];// 4
    AudioFileID                  mAudioFile;                    // 5
    UInt32                       bufferByteSize;                // 6
    SInt64                       mCurrentPacket;                // 7
    bool                         mIsRunning;                    // 8
}AQRecorderState;

録音用の私の設定パラメータは次のとおりです。

    ars.mDataFormat.mSampleRate     = 44100;
    ars.mDataFormat.mChannelsPerFrame   = 1;
    ars.mDataFormat.mFramesPerPacket    = 1;
    ars.mDataFormat.mBitsPerChannel     = 16;
    ars.mDataFormat.mBytesPerFrame      = ars.mDataFormat.mChannelsPerFrame * sizeof (SInt16); // BYTES_PER_FRAME;
    ars.mDataFormat.mBytesPerPacket     = ars.mDataFormat.mChannelsPerFrame * sizeof (SInt16); // BYTES_PER_PACKET;

    /*----------------- FORMAT -------------------*/
    ars.mDataFormat.mFormatID = kAudioFormatLinearPCM;
    ars.mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;

    // derive the buffer size
    DeriveBufferSize(ars.mQueue, ars.mDataFormat, kBufferSeconds, &ars.bufferByteSize);

    // create the queue
    AudioQueueNewInput(&ars.mDataFormat,
                       AQInputCallback,
                       (__bridge void *)(self),
                       NULL,
                       kCFRunLoopCommonModes,
                       0,
                       &ars.mQueue);

// set the magic cookie for the queue
    setMagicCookieForFile(ars.mQueue, ars.mAudioFile);

    // allocate and enque the recording buffers
    for (int i=0; i<kNumberRecordBuffers; i++){
        AudioQueueAllocateBuffer(ars.mQueue, ars.bufferByteSize, &ars.mBuffers[i]);
        AudioQueueEnqueueBuffer(ars.mQueue, ars.mBuffers[i], 0, NULL);
    }

    // set current packet index and run state
    ars.mCurrentPacket = 0;
    ars.mIsRunning = true;

    // start the recording
    AudioQueueStart(ars.mQueue, NULL);

そして、私の入力コールバックは次のようになります:

static void AQInputCallback(void *aqRecorderState,
            AudioQueueRef                        inQ,
            AudioQueueBufferRef                  inBuffer,
            const AudioTimeStamp                 *timestamp,
            unsigned long                        inNumPackets,
            const AudioStreamPacketDescription   *mDataFormat)
{

    NSLog(@"........Callback called");
    AppDelegate *THIS=(__bridge AppDelegate *)aqRecorderState;
    AQRecorderState *pArs = &(THIS->ars);

    if (inNumPackets > 0) {
        write_audio_frame(THIS->oc, THIS->audio_st);
        // Stream audio frame
        uint8_t *data;

        AVCodecContext *codec;
        AVPacket packet;
        uint32_t size = inBuffer->mAudioDataByteSize;

        long sample_time_ms = (long)(timestamp->mSampleTime * 1000 / SAMPLE_RATE);

        codec = THIS->audio_st->codec;

        data = av_malloc(size*100);
        if (!data) {
            fprintf(stderr, "Couldn't allocate data for audio_frame\n");
            exit(1);
        }

        NSLog(@"Size 1 : %d",size);

        av_init_packet(&packet);
        packet.size = avcodec_encode_audio(codec, data, size, inBuffer->mAudioData);

        NSLog(@"Size 2: %d",packet.size);

        packet.data = data;
        packet.pts = sample_time_ms;
        packet.dts = sample_time_ms;
        packet.flags |= AV_PKT_FLAG_KEY;
        packet.duration = (size * 8 * 1024 * 1000000)/BITS_PER_CHANNEL;
        packet.stream_index = THIS->audio_st->index; //audio_st->index

        pArs->mCurrentPacket += inNumPackets;  // advance packet index pointer

        if (av_interleaved_write_frame(THIS->oc, &packet) != 0) {
            exit(1);
        }

        pArs->mCurrentPacket += inNumPackets;  // advance packet index pointer

        av_free(data);
    }

}

入力コールバックでデータを取得しています。ファイルに書き込んで再生するとうまくいきますが、ファイルに保存せずにそのデータを RTSP サーバーに直接送信する必要があります。

注:av_interleaved_write_frame()フレームをサーバーに書き込むために使用していますが、問題はAVPacket入力コールバックでの変換にあると思います。そのため、サーバー側で「順不同」のパケットを取得しています。

インターネットであらゆる場所を検索しましたが、機能するものが見つかりません。誰かがそれについて何か考えているなら助けてください。

4

1 に答える 1

0

tcp と udp のどちらを使用していますか。パケットの順序が正しくなく、パケットのドロップが udp の問題になると思います。ffmpeg は、必要に応じてパケットの並べ替えを行うことができます。

于 2012-12-15T21:14:50.860 に答える