Exemple #1
0
// Filter len bytes of input, put result into outbuf.
static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf,
                          int len)
{
    int error = 0;

    struct mp_audio config;
    mp_audio_buffer_get_format(da->decode_buffer, &config);

    while (mp_audio_buffer_samples(da->decode_buffer) < len) {
        int maxlen = mp_audio_buffer_get_write_available(da->decode_buffer);
        if (maxlen < DECODE_MAX_UNIT)
            break;
        struct mp_audio buffer;
        mp_audio_buffer_get_write_buffer(da->decode_buffer, maxlen, &buffer);
        buffer.samples = 0;
        error = da->ad_driver->decode_audio(da, &buffer, maxlen);
        if (error < 0)
            break;
        // Commit the data just read as valid data
        mp_audio_buffer_finish_write(da->decode_buffer, buffer.samples);
        // Format change
        if (!mp_audio_config_equals(&da->decoded, &config)) {
            // If there are still samples left in the buffer, let them drain
            // first, and don't signal a format change to the caller yet.
            if (mp_audio_buffer_samples(da->decode_buffer) > 0)
                break;
            error = -2;
            break;
        }
    }

    // Filter
    struct mp_audio filter_data;
    mp_audio_buffer_peek(da->decode_buffer, &filter_data);
    filter_data.rate = da->afilter->input.rate; // due to playback speed change
    len = MPMIN(filter_data.samples, len);
    filter_data.samples = len;
    bool eof = filter_data.samples == 0 && error < 0;

    if (af_filter(da->afilter, &filter_data, eof ? AF_FILTER_FLAG_EOF : 0) < 0)
        return -1;

    mp_audio_buffer_append(outbuf, &filter_data);
    if (eof && filter_data.samples > 0)
        error = 0; // don't end playback yet

    // remove processed data from decoder buffer:
    mp_audio_buffer_skip(da->decode_buffer, len);

    // Assume the filter chain is drained from old data at this point.
    // (If not, the remaining old data is discarded.)
    if (error == -2) {
        if (!reinit_audio_buffer(da))
            error = -1; // switch to invalid format
    }

    return error;
}
Exemple #2
0
/* Decode packets until we know the audio format. Then reinit the buffer.
 * Returns AD_OK on success, negative AD_* code otherwise.
 * Also returns AD_OK if already initialized (and does nothing).
 */
int initial_audio_decode(struct dec_audio *da)
{
    while (!mp_audio_config_valid(&da->decoded)) {
        if (da->decoded.samples > 0)
            return AD_ERR; // invalid format, rather than uninitialized
        int ret = da->ad_driver->decode_packet(da);
        if (ret < 0)
            return ret;
    }
    if (mp_audio_buffer_samples(da->decode_buffer) > 0) // avoid accidental flush
        return AD_OK;
    return reinit_audio_buffer(da) ? AD_OK : AD_ERR;
}
Exemple #3
0
static int init_audio_codec(struct dec_audio *d_audio, const char *decoder)
{
    if (!d_audio->ad_driver->init(d_audio, decoder)) {
        MP_VERBOSE(d_audio, "Audio decoder init failed.\n");
        d_audio->ad_driver = NULL;
        uninit_decoder(d_audio);
        return 0;
    }

    d_audio->decode_buffer = mp_audio_buffer_create(NULL);
    if (!reinit_audio_buffer(d_audio)) {
        uninit_decoder(d_audio);
        return 0;
    }

    return 1;
}
Exemple #4
0
static int init_audio_codec(struct dec_audio *d_audio, const char *decoder)
{
    if (!d_audio->ad_driver->init(d_audio, decoder)) {
        mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Audio decoder init failed.\n");
        d_audio->ad_driver = NULL;
        uninit_decoder(d_audio);
        return 0;
    }

    if (!d_audio->decoded.channels.num || !d_audio->decoded.rate ||
        !d_audio->decoded.format)
    {
        mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder did not specify "
                "audio format!\n");
        uninit_decoder(d_audio);
        return 0;
    }

    d_audio->decode_buffer = mp_audio_buffer_create(NULL);
    reinit_audio_buffer(d_audio);

    return 1;
}
Exemple #5
0
// Filter len bytes of input, put result into outbuf.
static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf,
                          int len)
{
    bool format_change = false;
    int error = 0;

    assert(len > 0); // would break EOF logic below

    while (mp_audio_buffer_samples(da->decode_buffer) < len) {
        // Check for a format change
        struct mp_audio config;
        mp_audio_buffer_get_format(da->decode_buffer, &config);
        format_change = !mp_audio_config_equals(&da->decoded, &config);
        if (format_change) {
            error = AD_EOF; // drain remaining data left in the current buffer
            break;
        }
        if (da->decoded.samples > 0) {
            int copy = MPMIN(da->decoded.samples, len);
            struct mp_audio append = da->decoded;
            append.samples = copy;
            mp_audio_buffer_append(da->decode_buffer, &append);
            mp_audio_skip_samples(&da->decoded, copy);
            da->pts_offset += copy;
            continue;
        }
        error = da->ad_driver->decode_packet(da);
        if (error < 0)
            break;
    }

    if (error == AD_WAIT)
        return error;

    // Filter
    struct mp_audio filter_data;
    mp_audio_buffer_peek(da->decode_buffer, &filter_data);
    filter_data.rate = da->afilter->input.rate; // due to playback speed change
    len = MPMIN(filter_data.samples, len);
    filter_data.samples = len;
    bool eof = error == AD_EOF && filter_data.samples == 0;

    if (af_filter(da->afilter, &filter_data, eof ? AF_FILTER_FLAG_EOF : 0) < 0)
        return AD_ERR;

    mp_audio_buffer_append(outbuf, &filter_data);
    if (error == AD_EOF && filter_data.samples > 0)
        error = 0; // don't end playback yet

    // remove processed data from decoder buffer:
    mp_audio_buffer_skip(da->decode_buffer, len);

    // if format was changed, and all data was drained, execute the format change
    if (format_change && eof) {
        error = AD_NEW_FMT;
        if (!reinit_audio_buffer(da))
            error = AD_ERR; // switch to invalid format
    }

    return error;
}