Exemplo n.º 1
0
callback_info *init_callback_info(void)
{
    callback_info *info;

    if ((info = malloc (sizeof (callback_info))) == NULL)
    {
        FLACNG_ERROR("Could not allocate memory for callback structure!");
        return NULL;
    }

    memset (info, 0, sizeof (callback_info));

    if ((info->output_buffer = malloc (BUFFER_SIZE_BYTE)) == NULL)
    {
        FLACNG_ERROR("Could not allocate memory for output buffer!");
        free (info);
        return NULL;
    }

    reset_info(info);

    AUDDBG("Playback buffer allocated for %d samples, %d bytes\n", BUFFER_SIZE_SAMP, BUFFER_SIZE_BYTE);

    return info;
}
Exemplo n.º 2
0
static size_t read_cb(void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
{
    size_t read;

    if (handle == NULL)
    {
        FLACNG_ERROR("Trying to read data from an uninitialized file!\n");
        return -1;
    }

    read = vfs_fread(ptr, size, nmemb, handle);

    switch (read)
    {
        case -1:
            FLACNG_ERROR("Error while reading from stream!\n");
            return -1;

        case 0:
            AUDDBG("Stream reached EOF\n");
            return 0;

        default:
            return read;
    }
}
FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
{
    callback_info* info = (callback_info*) client_data;
    size_t read;

    if (info->fd == NULL)
    {
        FLACNG_ERROR("Trying to read data from an uninitialized file!\n");
        return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
    }

    if (*bytes == 0)
        return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;

    read = vfs_fread(buffer, 1, *bytes, info->fd);
    *bytes = read;

    switch (read)
    {
    case -1:
        FLACNG_ERROR("Error while reading from stream!\n");
        return FLAC__STREAM_DECODER_READ_STATUS_ABORT;

    case 0:
        AUDDBG("Stream reached EOF\n");
        return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;

    default:
        return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
    }
}
Exemplo n.º 4
0
bool_t read_metadata(FLAC__StreamDecoder *decoder, callback_info *info)
{
    FLAC__StreamDecoderState ret;

    reset_info(info);

    /* Reset the decoder */
    if (FLAC__stream_decoder_reset(decoder) == false)
    {
        FLACNG_ERROR("Could not reset the decoder!\n");
        return FALSE;
    }

    /* Try to decode the metadata */
    if (FLAC__stream_decoder_process_until_end_of_metadata(decoder) == false)
    {
        ret = FLAC__stream_decoder_get_state(decoder);
        AUDDBG("Could not read the metadata: %s(%d)!\n",
            FLAC__StreamDecoderStateString[ret], ret);
        reset_info(info);
        return FALSE;
    }

    return TRUE;
}
Exemplo n.º 5
0
static void squeeze_audio(int32_t* src, void* dst, unsigned count, unsigned res)
{
    int i;
    int32_t* rp = src;
    int8_t*  wp = dst;
    int16_t* wp2 = dst;
    int32_t* wp4 = dst;

    switch (res)
    {
        case 8:
            for (i = 0; i < count; i++, wp++, rp++)
                *wp = *rp & 0xff;
            break;

        case 16:
            for (i = 0; i < count; i++, wp2++, rp++)
                *wp2 = *rp & 0xffff;
            break;

        case 24:
        case 32:
            for (i = 0; i < count; i++, wp4++, rp++)
                *wp4 = *rp;
            break;

        default:
            FLACNG_ERROR("Can not convert to %u bps\n", res);
    }
}
FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
{
    glong sample;
    gshort channel;
    callback_info *info = (callback_info*) client_data;

    /*
     * Check if there is more data decoded than we have space
     * for. This _should_ not happen given how our buffer is sized,
     * but you never know.
     */
    if (info->buffer_free < (frame->header.blocksize * frame->header.channels))
    {
        FLACNG_ERROR("BUG! Too much data decoded from stream!\n");
        return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
    }

    if (frame->header.bits_per_sample != 8  &&
            frame->header.bits_per_sample != 16 &&
            frame->header.bits_per_sample != 24 &&
            frame->header.bits_per_sample != 32)
    {
        FLACNG_ERROR("Unsupported bitrate found in stream: %d!\n", frame->header.bits_per_sample);
        return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
    }

    /*
     * Copy the frame metadata, will be compared to stream
     * metadata later
     * This also describes the format of the current buffer content.
     */
    info->frame.channels = frame->header.channels;
    info->frame.samplerate = frame->header.sample_rate;
    info->frame.bits_per_sample = frame->header.bits_per_sample;

    for (sample = 0; sample < frame->header.blocksize; sample++)
    {
        for (channel = 0; channel < frame->header.channels; channel++)
        {
            *(info->write_pointer++) = buffer[channel][sample];
            info->buffer_free -= 1;
            info->buffer_used += 1;
        }
    }

    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
Exemplo n.º 7
0
static int seek_cb(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
{
    if (vfs_fseek(handle, offset, whence) != 0)
    {
        FLACNG_ERROR("Could not seek to %ld!\n", (long)offset);
        return -1;
    }

    return 0;
}
Exemplo n.º 8
0
bool_t flac_update_song_tuple(const char *filename, VFSFile *fd, const Tuple *tuple)
{
    AUDDBG("Update song tuple.\n");

    FLAC__Metadata_Iterator *iter;
    FLAC__Metadata_Chain *chain;
    FLAC__StreamMetadata *vc_block;
    FLAC__Metadata_ChainStatus status;

    chain = FLAC__metadata_chain_new();

    if (!FLAC__metadata_chain_read_with_callbacks(chain, fd, io_callbacks))
        goto ERR;

    iter = FLAC__metadata_iterator_new();

    FLAC__metadata_iterator_init(iter, chain);

    while (FLAC__metadata_iterator_next(iter))
        if (FLAC__metadata_iterator_get_block_type(iter) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
        {
            FLAC__metadata_iterator_delete_block(iter, true);
            break;
        }

    vc_block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);

    insert_str_tuple_to_vc(vc_block, tuple, FIELD_TITLE, "TITLE");
    insert_str_tuple_to_vc(vc_block, tuple, FIELD_ARTIST, "ARTIST");
    insert_str_tuple_to_vc(vc_block, tuple, FIELD_ALBUM, "ALBUM");
    insert_str_tuple_to_vc(vc_block, tuple, FIELD_GENRE, "GENRE");
    insert_str_tuple_to_vc(vc_block, tuple, FIELD_COMMENT, "COMMENT");
    insert_str_tuple_to_vc(vc_block, tuple, FIELD_MBID, "musicbrainz_trackid");

    insert_int_tuple_to_vc(vc_block, tuple, FIELD_YEAR, "DATE");
    insert_int_tuple_to_vc(vc_block, tuple, FIELD_TRACK_NUMBER, "TRACKNUMBER");

    FLAC__metadata_iterator_insert_block_after(iter, vc_block);

    FLAC__metadata_iterator_delete(iter);
    FLAC__metadata_chain_sort_padding(chain);

    if (!FLAC__metadata_chain_write_with_callbacks(chain, TRUE, fd, io_callbacks))
        goto ERR;

    FLAC__metadata_chain_delete(chain);
    return TRUE;

ERR:
    status = FLAC__metadata_chain_status(chain);
    FLAC__metadata_chain_delete(chain);

    FLACNG_ERROR("An error occured: %s\n", FLAC__Metadata_ChainStatusString[status]);
    return FALSE;
}
FLAC__StreamDecoderSeekStatus seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 offset, void *client_data)
{
    callback_info *info = (callback_info*) client_data;

    if (vfs_fseek(info->fd, offset, SEEK_SET) != 0)
    {
        FLACNG_ERROR("Could not seek to %lld!\n", (long long)offset);
        return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
    }

    return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
Exemplo n.º 10
0
static FLAC__int64 tell_cb(FLAC__IOHandle handle)
{
    uint64_t offset;

    if ((offset = vfs_ftell(handle)) == -1)
    {
        FLACNG_ERROR("Could not tell current position!\n");
        return -1;
    }

    AUDDBG ("Current position: %d\n", (int) offset);
    return offset;
}
Exemplo n.º 11
0
static bool_t flac_init (void)
{
    FLAC__StreamDecoderInitStatus ret;

    /* Callback structure and decoder for main decoding loop */

    if ((info = init_callback_info()) == NULL)
    {
        FLACNG_ERROR("Could not initialize the main callback structure!\n");
        return FALSE;
    }

    if ((decoder = FLAC__stream_decoder_new()) == NULL)
    {
        FLACNG_ERROR("Could not create the main FLAC decoder instance!\n");
        return FALSE;
    }

    if (FLAC__STREAM_DECODER_INIT_STATUS_OK != (ret = FLAC__stream_decoder_init_stream(
        decoder,
        read_callback,
        seek_callback,
        tell_callback,
        length_callback,
        eof_callback,
        write_callback,
        metadata_callback,
        error_callback,
        info)))
    {
        FLACNG_ERROR("Could not initialize the main FLAC decoder: %s(%d)\n",
            FLAC__StreamDecoderInitStatusString[ret], ret);
        return FALSE;
    }

    AUDDBG("Plugin initialized.\n");
    return TRUE;
}
Exemplo n.º 12
0
bool_t flac_get_image(const char *filename, VFSFile *fd, void **data, int64_t *length)
{
    AUDDBG("Probe for song image.\n");

    FLAC__Metadata_Iterator *iter;
    FLAC__Metadata_Chain *chain;
    FLAC__StreamMetadata *metadata = NULL;
    FLAC__Metadata_ChainStatus status;
    bool_t has_image = FALSE;

    chain = FLAC__metadata_chain_new();

    if (!FLAC__metadata_chain_read_with_callbacks(chain, fd, io_callbacks))
        goto ERR;

    iter = FLAC__metadata_iterator_new();

    FLAC__metadata_iterator_init(iter, chain);

    while (FLAC__metadata_iterator_next(iter))
        if (FLAC__metadata_iterator_get_block_type(iter) == FLAC__METADATA_TYPE_PICTURE)
            break;

    if (FLAC__metadata_iterator_get_block_type(iter) == FLAC__METADATA_TYPE_PICTURE)
    {
        metadata = FLAC__metadata_iterator_get_block(iter);

        if (metadata->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
        {
            AUDDBG("FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER found.");

            * data = malloc (metadata->data.picture.data_length);
            * length = metadata->data.picture.data_length;
            memcpy (* data, metadata->data.picture.data, * length);
            has_image = TRUE;
        }
    }

    FLAC__metadata_iterator_delete(iter);
    FLAC__metadata_chain_delete(chain);

    return has_image;

ERR:
    status = FLAC__metadata_chain_status(chain);
    FLAC__metadata_chain_delete(chain);

    FLACNG_ERROR("An error occured: %s\n", FLAC__Metadata_ChainStatusString[status]);
    return FALSE;
}
FLAC__StreamDecoderTellStatus tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *offset, void *client_data)
{
    callback_info *info = (callback_info*) client_data;

    if ((*offset = vfs_ftell(info->fd)) == -1)
    {
        FLACNG_ERROR("Could not tell current position!\n");
        return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
    }

    AUDDBG ("Current position: %d\n", (gint) * offset);

    return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
Exemplo n.º 14
0
Tuple *flac_probe_for_tuple(const char *filename, VFSFile *fd)
{
    AUDDBG("Probe for tuple.\n");

    Tuple *tuple = NULL;
    FLAC__Metadata_Iterator *iter;
    FLAC__Metadata_Chain *chain;
    FLAC__StreamMetadata *metadata = NULL;
    FLAC__Metadata_ChainStatus status;
    FLAC__StreamMetadata_VorbisComment_Entry *entry;
    char *key;
    char *value;

    tuple = tuple_new_from_filename(filename);

    tuple_set_str(tuple, FIELD_CODEC, NULL, "Free Lossless Audio Codec (FLAC)");
    tuple_set_str(tuple, FIELD_QUALITY, NULL, _("lossless"));

    chain = FLAC__metadata_chain_new();

    if (!FLAC__metadata_chain_read_with_callbacks(chain, fd, io_callbacks))
        goto ERR;

    iter = FLAC__metadata_iterator_new();

    FLAC__metadata_iterator_init(iter, chain);

    do
    {
        switch (FLAC__metadata_iterator_get_block_type(iter))
        {
            case FLAC__METADATA_TYPE_VORBIS_COMMENT:

                if (FLAC__metadata_iterator_get_block_type(iter) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
                {
                    metadata = FLAC__metadata_iterator_get_block(iter);

                    AUDDBG("Vorbis comment contains %d fields\n", metadata->data.vorbis_comment.num_comments);
                    AUDDBG("Vendor string: %s\n", metadata->data.vorbis_comment.vendor_string.entry);

                    entry = metadata->data.vorbis_comment.comments;

                    for (int i = 0; i < metadata->data.vorbis_comment.num_comments; i++, entry++)
                    {
                        if (FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(*entry, &key, &value) == false)
                            AUDDBG("Could not parse comment\n");
                        else
                        {
                            parse_comment(tuple, key, value);
                            free(key);
                            free(value);
                        }
                    }
                }
                break;

            case FLAC__METADATA_TYPE_STREAMINFO:
                metadata = FLAC__metadata_iterator_get_block(iter);

                /* Calculate the stream length (milliseconds) */
                if (metadata->data.stream_info.sample_rate == 0)
                {
                    FLACNG_ERROR("Invalid sample rate for stream!\n");
                    tuple_set_int(tuple, FIELD_LENGTH, NULL, -1);
                }
                else
                {
                    tuple_set_int(tuple, FIELD_LENGTH, NULL,
                        (metadata->data.stream_info.total_samples / metadata->data.stream_info.sample_rate) * 1000);
                    AUDDBG("Stream length: %d seconds\n", tuple_get_int(tuple, FIELD_LENGTH, NULL));
                }

                int64_t size = vfs_fsize(fd);

                if (size == -1 || metadata->data.stream_info.total_samples == 0)
                    tuple_set_int(tuple, FIELD_BITRATE, NULL, 0);
                else
                {
                    int bitrate = 8 * size *
                        (int64_t) metadata->data.stream_info.sample_rate / metadata->data.stream_info.total_samples;

                    tuple_set_int(tuple, FIELD_BITRATE, NULL, (bitrate + 500) / 1000);
                }
                break;

            default:
                ;
        }
    } while (FLAC__metadata_iterator_next(iter));

    FLAC__metadata_iterator_delete(iter);
    FLAC__metadata_chain_delete(chain);

    return tuple;

ERR:
    status = FLAC__metadata_chain_status(chain);
    FLAC__metadata_chain_delete(chain);

    FLACNG_ERROR("An error occured: %s\n", FLAC__Metadata_ChainStatusString[status]);
    return tuple;
}
Exemplo n.º 15
0
static bool_t flac_play (const char * filename, VFSFile * file)
{
    if (!file)
        return FALSE;

    void * play_buffer = NULL;
    bool_t error = FALSE;

    info->fd = file;

    if (read_metadata(decoder, info) == FALSE)
    {
        FLACNG_ERROR("Could not prepare file for playing!\n");
        error = TRUE;
        goto ERR_NO_CLOSE;
    }

    play_buffer = g_malloc (BUFFER_SIZE_BYTE);

    if (! aud_input_open_audio (SAMPLE_FMT (info->bits_per_sample),
        info->sample_rate, info->channels))
    {
        error = TRUE;
        goto ERR_NO_CLOSE;
    }

    aud_input_set_bitrate(info->bitrate);

    while (FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM)
    {
        if (aud_input_check_stop ())
            break;

        int seek_value = aud_input_check_seek ();
        if (seek_value >= 0)
            FLAC__stream_decoder_seek_absolute (decoder, (int64_t)
             seek_value * info->sample_rate / 1000);

        /* Try to decode a single frame of audio */
        if (FLAC__stream_decoder_process_single(decoder) == FALSE)
        {
            FLACNG_ERROR("Error while decoding!\n");
            error = TRUE;
            break;
        }

        squeeze_audio(info->output_buffer, play_buffer, info->buffer_used, info->bits_per_sample);
        aud_input_write_audio(play_buffer, info->buffer_used * SAMPLE_SIZE(info->bits_per_sample));

        reset_info(info);
    }

ERR_NO_CLOSE:
    g_free (play_buffer);
    reset_info(info);

    if (FLAC__stream_decoder_flush(decoder) == FALSE)
        FLACNG_ERROR("Could not flush decoder state!\n");

    return ! error;
}
void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
{
    FLACNG_ERROR("FLAC decoder error callback was called: %d\n", status);
}