summaryrefslogtreecommitdiffstats
path: root/audio/decode
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-01-13 20:15:43 +0100
committerwm4 <wm4@nowhere>2015-01-13 20:15:43 +0100
commit5e25a3d2168555efea9cbd7eb2846d44ede1948d (patch)
treed5c9fa8180c4f35b062cd2291ebb589d7d58be03 /audio/decode
parent97becbc31bfd6acb76f584eaf65c1546d6fbcc8b (diff)
downloadmpv-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.c61
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) {