diff options
author | wm4 <wm4@nowhere> | 2015-01-13 20:15:43 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2015-01-13 20:15:43 +0100 |
commit | 5e25a3d2168555efea9cbd7eb2846d44ede1948d (patch) | |
tree | d5c9fa8180c4f35b062cd2291ebb589d7d58be03 /audio/decode | |
parent | 97becbc31bfd6acb76f584eaf65c1546d6fbcc8b (diff) | |
download | mpv-5e25a3d2168555efea9cbd7eb2846d44ede1948d.tar.bz2 mpv-5e25a3d2168555efea9cbd7eb2846d44ede1948d.tar.xz |
audio: use refcounted frames in the filter chain
The goal is switching the whole audio chain to using refcounted frames.
This brings the architecture closer to FFmpeg, enables better
integration with libavfilter, will reduce useless copying somewhat, and
will probably allow better timestamp tracking.
For now, every filter goes through a semi-awful wrapper in
af_do_filter(), though. This will be fixed step by step, and the wrapper
should eventually be removed. Another thing that will have to be done is
improving the timestamp handling and avoiding extra copies for the AO.
Some of the new code is rather similar to the video filter code (the
core filter code basically just has types replaced). Such code
duplication is normally very unwanted, but in this case there's probably
no other choice. On the other hand, this code is pretty simple (even if
somewhat tricky). Maybe there will be unified filter code in the future,
but this is still far away.
Diffstat (limited to 'audio/decode')
-rw-r--r-- | audio/decode/dec_audio.c | 61 |
1 files changed, 37 insertions, 24 deletions
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c index da541de674..3c196709c8 100644 --- a/audio/decode/dec_audio.c +++ b/audio/decode/dec_audio.c @@ -172,6 +172,21 @@ int initial_audio_decode(struct dec_audio *da) return mp_audio_config_valid(da->waiting) ? AD_OK : AD_ERR; } +static bool copy_output(struct af_stream *afs, struct mp_audio_buffer *outbuf, + int minsamples, bool eof) +{ + while (mp_audio_buffer_samples(outbuf) < minsamples) { + if (af_output_frame(afs, eof) < 0) + return true; // error, stop doing stuff + struct mp_audio *mpa = af_read_output_frame(afs); + if (!mpa) + return false; // out of data + mp_audio_buffer_append(outbuf, mpa); + talloc_free(mpa); + } + return true; +} + /* Try to get at least minsamples decoded+filtered samples in outbuf * (total length including possible existing data). * Return 0 on success, or negative AD_* error code. @@ -186,41 +201,39 @@ int audio_decode(struct dec_audio *da, struct mp_audio_buffer *outbuf, MP_STATS(da, "start audio"); - int res = 0; - while (res >= 0 && minsamples >= 0) { - int buffered = mp_audio_buffer_samples(outbuf); - if (minsamples < buffered) - break; - + int res; + while (1) { res = 0; + if (copy_output(afs, outbuf, minsamples, false)) + break; + struct mp_audio *mpa = da->waiting; - if (!mpa) + da->waiting = NULL; + if (!mpa) { res = da->ad_driver->decode_packet(da, &mpa); - - if (res != AD_EOF) { - if (res < 0) + if (res < 0) { + // drain filters first (especially for true EOF case) + copy_output(afs, outbuf, minsamples, true); break; - if (!mpa ) - continue; - } + } + + assert(mpa); - if (mpa) { da->pts_offset += mpa->samples; da->decode_format = *mpa; mp_audio_set_null_data(&da->decode_format); - // On format change, make sure to drain the filter chain. - if (!mp_audio_config_equals(&afs->input, mpa)) { - res = AD_NEW_FMT; - da->waiting = talloc_steal(da, mpa); - mpa = NULL; - } } - if (mpa) - da->waiting = NULL; + // On format change, make sure to drain the filter chain. + if (!mp_audio_config_equals(&afs->input, mpa)) { + da->waiting = talloc_steal(da, mpa); + copy_output(afs, outbuf, minsamples, true); + res = AD_NEW_FMT; + break; + } - if (af_filter(afs, mpa, outbuf) < 0) + if (af_filter_frame(afs, mpa) < 0) return AD_ERR; } @@ -233,7 +246,7 @@ void audio_reset_decoding(struct dec_audio *d_audio) { if (d_audio->ad_driver) d_audio->ad_driver->control(d_audio, ADCTRL_RESET, NULL); - af_control_all(d_audio->afilter, AF_CONTROL_RESET, NULL); + af_seek_reset(d_audio->afilter); d_audio->pts = MP_NOPTS_VALUE; d_audio->pts_offset = 0; if (d_audio->waiting) { |