Exemplo n.º 1
0
static int build_afilter_chain(struct MPContext *mpctx)
{
    struct dec_audio *d_audio = mpctx->d_audio;
    struct MPOpts *opts = mpctx->opts;

    if (!d_audio)
        return 0;

    struct mp_audio in_format;
    mp_audio_buffer_get_format(d_audio->decode_buffer, &in_format);

    struct mp_audio out_format;
    ao_get_format(mpctx->ao, &out_format);

    int new_srate;
    if (af_control_any_rev(d_audio->afilter, AF_CONTROL_SET_PLAYBACK_SPEED,
                           &opts->playback_speed))
        new_srate = in_format.rate;
    else {
        new_srate = in_format.rate * opts->playback_speed;
        if (new_srate != out_format.rate) {
            // limits are taken from libaf/af_resample.c
            if (new_srate < 8000)
                new_srate = 8000;
            if (new_srate > 192000)
                new_srate = 192000;
            opts->playback_speed = new_srate / (double)in_format.rate;
        }
    }
    return audio_init_filters(d_audio, new_srate,
                              &out_format.rate, &out_format.channels, &out_format.format);
}
Exemplo n.º 2
0
Arquivo: audio.c Projeto: bagobor/mpv
static int recreate_audio_filters(struct MPContext *mpctx)
{
    assert(mpctx->d_audio);

    struct af_stream *afs = mpctx->d_audio->afilter;
    struct MPOpts *opts = mpctx->opts;

    struct mp_audio in_format;
    mp_audio_buffer_get_format(mpctx->d_audio->decode_buffer, &in_format);
    int new_srate = in_format.rate;

    if (!af_control_any_rev(afs, AF_CONTROL_SET_PLAYBACK_SPEED,
                            &opts->playback_speed))
    {
        new_srate = in_format.rate * opts->playback_speed;
        if (new_srate != afs->output.rate)
            opts->playback_speed = new_srate / (double)in_format.rate;
    }
    afs->input.rate = new_srate;

    if (af_init(afs) < 0) {
        MP_ERR(mpctx, "Couldn't find matching filter/ao format!\n");
        return -1;
    }

    mixer_reinit_audio(mpctx->mixer, mpctx->ao, afs);

    return 0;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
int audio_init_filters(struct dec_audio *d_audio, int in_samplerate,
                       int *out_samplerate, struct mp_chmap *out_channels,
                       int *out_format)
{
    if (!d_audio->afilter)
        d_audio->afilter = af_new(d_audio->global);
    struct af_stream *afs = d_audio->afilter;

    // input format: same as codec's output format:
    mp_audio_buffer_get_format(d_audio->decode_buffer, &afs->input);
    // Sample rate can be different when adjusting playback speed
    afs->input.rate = in_samplerate;

    // output format: same as ao driver's input format (if missing, fallback to input)
    afs->output.rate = *out_samplerate;
    mp_audio_set_channels(&afs->output, out_channels);
    mp_audio_set_format(&afs->output, *out_format);

    afs->metadata = d_audio->metadata;

    afs->replaygain_data = d_audio->replaygain_data;

    char *s_from = mp_audio_config_to_str(&afs->input);
    char *s_to = mp_audio_config_to_str(&afs->output);
    MP_VERBOSE(d_audio, "Building audio filter chain for %s -> %s...\n", s_from, s_to);
    talloc_free(s_from);
    talloc_free(s_to);

    // let's autoprobe it!
    if (af_init(afs) != 0) {
        af_destroy(afs);
        d_audio->afilter = NULL;
        return 0;   // failed :(
    }

    *out_samplerate = afs->output.rate;
    *out_channels = afs->output.channels;
    *out_format = afs->output.format;

    return 1;
}
Exemplo n.º 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;
}