Chunked Encoding using Flac on iOS

前端 未结 3 1277
北恋
北恋 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:25

    can't you record your audio in wav using audio queue services and process output packets with your lib ?

    edit from apple dev doc : "Applications writing AIFF and WAV files must either update the data header’s size field at the end of recording—which can result in an unusable file if recording is interrupted before the header is finalized—or they must update the size field after recording each packet of data, which is inefficient."

    apparently it seems quite hard to encode a wav file on the fly

    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2021-02-04 23:37

    Your question is not very specific, but you need to use Audio Recording Services, which will let you get access to the audio data in chunks, and then move the data you get from there into the streaming interface of the FLAC encoder. You can not use the WAV to FLAC program you linked to, you have to tap into the FLAC library yourself. API docs here.

    Example on how to use a callback here.

    0 讨论(0)
提交回复
热议问题