Chunked Encoding using Flac on iOS

前端 未结 3 1275
北恋
北恋 2021-02-04 23:02

I found a library that helps to convert WAV file to Flac: https://github.com/jhurt/wav_to_flac

Also succeed to compile Flac to the platform and it works fine.

I\

3条回答
  •  执念已碎
    2021-02-04 23:30

    In my library called libsprec, you can see an example of both recording a WAV file (here) and converting it to FLAC (here). (Credits: the audio recording part heavily relies on Erica Sadun's work, for the record.)

    Now if you want to do this in one step, you can do that as well. The trick is that you have to do the initialization of both the Audio Queues and the FLAC library first, then "interleave" the calls to them, i. e. when you get some audio data in the callback function of the Audio Queue, you immediately FLAC-encode it.

    I don't think, however, that this would be much faster than recording and encoding in two separate steps. The heavy part of the processing is the recording and the maths in the encoding itself, so re-reading the same buffer (or I dare you, even a file!) won't add much to the processing time.

    That said, you may want to do something like this:

    // First, we initialize the Audio Queue
    
    AudioStreamBasicDescription desc;
    desc.mFormatID = kAudioFormatLinearPCM;
    desc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
    desc.mReserved = 0;
    desc.mSampleRate = SAMPLE_RATE;
    desc.mChannelsPerFrame = 2; // stereo (?)
    desc.mBitsPerChannel = BITS_PER_SAMPLE;
    desc.mBytesPerFrame = BYTES_PER_FRAME;
    desc.mFramesPerPacket = 1;
    desc.mBytesPerPacket = desc.mFramesPerPacket * desc.mBytesPerFrame;
    
    AudioQueueRef queue;
    
    status = AudioQueueNewInput(
        &desc,
        audio_queue_callback, // our custom callback function
        NULL,
        NULL,
        NULL,
        0,
        &queue
    );
    
    if (status)
        return status;
    
    AudioQueueBufferRef buffers[NUM_BUFFERS];
    
    for (i = 0; i < NUM_BUFFERS; i++) {
        status = AudioQueueAllocateBuffer(
            queue,
            0x5000, // max buffer size
            &buffers[i]
        );
        if (status)
            return status;
    
        status = AudioQueueEnqueueBuffer(
            queue,
            buffers[i],
            0,
            NULL
        );
        if (status)
            return status;
    }
    
    // Then, we initialize the FLAC encoder:
    FLAC__StreamEncoder *encoder;
    FLAC__StreamEncoderInitStatus status;
    FILE *infile;
    const char *dataloc;
    uint32_t rate;      /* sample rate */
    uint32_t total;     /* number of samples in file */
    uint32_t channels;  /* number of channels */
    uint32_t bps;       /* bits per sample */
    uint32_t dataoff;   /* offset of PCM data within the file */
    int err;
    
    /*
     * BUFFSIZE samples * 2 bytes per sample * 2 channels
     */
    FLAC__byte buffer[BUFSIZE * 2 * 2];
    
    /*
     * BUFFSIZE samples * 2 channels
     */
    FLAC__int32 pcm[BUFSIZE * 2];
    
    
    /*
     * Create and initialize the FLAC encoder
     */
    encoder = FLAC__stream_encoder_new();
    if (!encoder)
        return -1;
    
    
    FLAC__stream_encoder_set_verify(encoder, true);
    FLAC__stream_encoder_set_compression_level(encoder, 5);
    FLAC__stream_encoder_set_channels(encoder, NUM_CHANNELS); // 2 for stereo
    FLAC__stream_encoder_set_bits_per_sample(encoder, BITS_PER_SAMPLE); // 32 for stereo 16 bit per channel
    FLAC__stream_encoder_set_sample_rate(encoder, SAMPLE_RATE);
    
    status = FLAC__stream_encoder_init_stream(encoder, flac_callback, NULL, NULL, NULL, NULL);
    if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
        return -1;
    
    
    // We now start the Audio Queue...
    status = AudioQueueStart(queue, NULL);
    
    // And when it's finished, we clean up the FLAC encoder...
    FLAC__stream_encoder_finish(encoder);
    FLAC__stream_encoder_delete(encoder);
    
    // and the audio queue and its belongings too
    AudioQueueFlush(queue);
    AudioQueueStop(queue, false);
    
    for (i = 0; i < NUM_BUFFERS; i++)
        AudioQueueFreeBuffer(queue, buffers[i]);
    
    AudioQueueDispose(queue, true);
    
    // In the audio queue callback function, we do the encoding:
    
    void audio_queue_callback(
        void *data,
        AudioQueueRef inAQ,
        AudioQueueBufferRef buffer,
        const AudioTimeStamp *start_time,
        UInt32 num_packets,
        const AudioStreamPacketDescription *desc
    )
    {
        unsigned char *buf = buffer->mAudioData;
    
        for (size_t i = 0; i < num_packets * channels; i++) {
            uint16_t msb = *(uint8_t *)(buf + i * 2 + 1);
            uint16_t usample = (msb << 8) | lsb;
    
            union {
                uint16_t usample;
                int16_t  ssample;
            } u;
    
            u.usample = usample;
            pcm[i] = u.ssample;
        }
    
        FLAC__bool succ = FLAC__stream_encoder_process_interleaved(encoder, pcm, num_packets);
        if (!succ)
            // handle_error();
    }
    
    // Finally, in the FLAC stream encoder callback:
    
    FLAC__StreamEncoderWriteStatus flac_callback(
        const FLAC__StreamEncoder *encoder,
        const FLAC__byte buffer[],
        size_t bytes,
        unsigned samples,
        unsigned current_frame,
        void *client_data
    )
    {
        // Here process `buffer' and stuff,
        // then:
    
        return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
    }
    

    You are welcome.

提交回复
热议问题