summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libaf/af.c23
-rw-r--r--libaf/af.h20
-rw-r--r--libmpcodecs/dec_audio.c174
-rw-r--r--libmpcodecs/dec_audio.h2
-rw-r--r--mencoder.c9
-rw-r--r--mplayer.c20
6 files changed, 115 insertions, 133 deletions
diff --git a/libaf/af.c b/libaf/af.c
index 5eda4ff5b1..b86bfe3d14 100644
--- a/libaf/af.c
+++ b/libaf/af.c
@@ -526,19 +526,9 @@ int af_lencalc(double mul, af_data_t* d)
return d->len * mul + t + 1;
}
-/* Calculate how long the input IN to the filters should be to produce
- a certain output length OUT but with the following three constraints:
- 1. IN <= max_insize, where max_insize is the maximum possible input
- block length
- 2. OUT <= max_outsize, where max_outsize is the maximum possible
- output block length
- 3. If possible OUT >= len.
- Return -1 in case of error */
-int af_calc_insize_constrained(af_stream_t* s, int len,
- int max_outsize,int max_insize)
+// Calculate average ratio of filter output size to input size
+double af_calc_filter_multiplier(af_stream_t* s)
{
- int t = s->input.bps*s->input.nch;
- int in = 0;
af_instance_t* af=s->first;
double mul = 1;
// Iterate through all filters and calculate total multiplication factor
@@ -547,14 +537,7 @@ int af_calc_insize_constrained(af_stream_t* s, int len,
af=af->next;
}while(af);
- if (len > max_outsize)
- len = max_outsize;
-
- in = len / t / mul * t;
-
- if(in>max_insize) in=t*(max_insize/t);
-
- return in;
+ return mul;
}
/* Calculate the total delay [ms] caused by the filters */
diff --git a/libaf/af.h b/libaf/af.h
index 428f53ff6e..4c983cb6e4 100644
--- a/libaf/af.h
+++ b/libaf/af.h
@@ -189,22 +189,10 @@ af_data_t* af_play(af_stream_t* s, af_data_t* data);
af_instance_t *af_control_any_rev (af_stream_t* s, int cmd, void* arg);
/**
- * \brief calculate required input length for desired output size
- * \param len desired minimum output length
- * \param max_outsize maximum output length
- * \param max_insize maximum input length
- * \return input length or -1 on error
- *
- Calculate how long the input IN to the filters should be to produce
- a certain output length OUT but with the following three constraints:
- 1. IN <= max_insize, where max_insize is the maximum possible input
- block length
- 2. OUT <= max_outsize, where max_outsize is the maximum possible
- output block length
- 3. If possible OUT >= len.
- */
-int af_calc_insize_constrained(af_stream_t* s, int len,
- int max_outsize,int max_insize);
+ * \brief calculate average ratio of filter output lenth to input length
+ * \return the ratio
+ */
+double af_calc_filter_multiplier(af_stream_t* s);
/**
* \brief Calculate the total delay caused by the filters
diff --git a/libmpcodecs/dec_audio.c b/libmpcodecs/dec_audio.c
index 5445eeac22..ee6295d2ca 100644
--- a/libmpcodecs/dec_audio.c
+++ b/libmpcodecs/dec_audio.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <assert.h>
#include "config.h"
#include "mp_msg.h"
@@ -380,86 +381,113 @@ int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
return 1;
}
-int decode_audio(sh_audio_t *sh_audio, unsigned char *buf, int minlen,
- int maxlen)
+static int filter_n_bytes(sh_audio_t *sh, int len)
{
- int declen;
- af_data_t afd; // filter input
- af_data_t *pafd; // filter output
- ad_functions_t *mpadec = sh_audio->ad_driver;
-
- if (!sh_audio->inited || !sh_audio->afilter)
- abort();
-
- declen = af_calc_insize_constrained(sh_audio->afilter, minlen, maxlen,
- sh_audio->a_buffer_size -
- sh_audio->audio_out_minsize);
-
- mp_msg(MSGT_DECAUDIO, MSGL_DBG2,
- "\ndecaudio: minlen=%d maxlen=%d declen=%d (max=%d)\n", minlen,
- maxlen, declen, sh_audio->a_buffer_size);
-
- if (declen <= 0)
- return -1; // error!
-
- while (declen > sh_audio->a_buffer_len) {
- int len = declen - sh_audio->a_buffer_len;
- int maxlen = sh_audio->a_buffer_size - sh_audio->a_buffer_len;
-
- mp_msg(MSGT_DECAUDIO, MSGL_DBG2,
- "decaudio: decoding %d bytes, max: %d (%d)\n", len, maxlen,
- sh_audio->audio_out_minsize);
-
- // When a decoder sets audio_out_minsize that should guarantee it can
- // write up to audio_out_minsize bytes at a time until total >= minlen
- // without checking maxlen. Thus maxlen must be at least minlen +
- // audio_out_minsize. Check that to guard against buffer overflows.
- if (maxlen < len + sh_audio->audio_out_minsize)
+ assert(len-1 + sh->audio_out_minsize <= sh->a_buffer_size);
+
+ int error = 0;
+
+ // Decode more bytes if needed
+ while (sh->a_buffer_len < len) {
+ unsigned char *buf = sh->a_buffer + sh->a_buffer_len;
+ int minlen = len - sh->a_buffer_len;
+ int maxlen = sh->a_buffer_size - sh->a_buffer_len;
+ int ret = sh->ad_driver->decode_audio(sh, buf, minlen, maxlen);
+ if (ret <= 0) {
+ error = -1;
+ len = sh->a_buffer_len;
break;
+ }
+ sh->a_buffer_len += ret;
+ }
- len = mpadec->decode_audio(sh_audio,
- sh_audio->a_buffer + sh_audio->a_buffer_len,
- len, maxlen);
- if (len <= 0)
- break; // EOF?
- sh_audio->a_buffer_len += len;
+ // Filter
+ af_data_t filter_input = {
+ .audio = sh->a_buffer,
+ .len = len,
+ .rate = sh->samplerate,
+ .nch = sh->channels,
+ .format = sh->sample_format
+ };
+ af_fix_parameters(&filter_input);
+ af_data_t *filter_output = af_play(sh->afilter, &filter_input);
+ if (!filter_output)
+ return -1;
+ if (sh->a_out_buffer_size < sh->a_out_buffer_len + filter_output->len) {
+ int newlen = sh->a_out_buffer_len + filter_output->len;
+ mp_msg(MSGT_DECAUDIO, MSGL_V, "Increasing filtered audio buffer size "
+ "from %d to %d\n", sh->a_out_buffer_size, newlen);
+ sh->a_out_buffer = realloc(sh->a_out_buffer, newlen);
+ sh->a_out_buffer_size = newlen;
}
- if (declen > sh_audio->a_buffer_len)
- declen = sh_audio->a_buffer_len; // still no enough data (EOF) :(
-
- // run the filters:
- afd.audio = sh_audio->a_buffer;
- afd.len = declen;
- afd.rate = sh_audio->samplerate;
- afd.nch = sh_audio->channels;
- afd.format = sh_audio->sample_format;
- af_fix_parameters(&afd);
- pafd = af_play(sh_audio->afilter, &afd);
-
- if (!pafd)
- return -1; // error
-
- mp_msg(MSGT_DECAUDIO, MSGL_DBG2, "decaudio: declen=%d out=%d (max %d)\n",
- declen, pafd->len, maxlen);
-
- // copy filter==>out:
- if (maxlen < pafd->len) {
- af_stream_t *afs = sh_audio->afilter;
- maxlen -= maxlen % (afs->output.nch * afs->output.bps);
- mp_msg(MSGT_DECAUDIO, MSGL_WARN,
- "%i bytes of audio data lost due to buffer overflow, len = %i\n",
- pafd->len - maxlen, pafd->len);
- } else
- maxlen = pafd->len;
- memmove(buf, pafd->audio, maxlen);
+ memcpy(sh->a_out_buffer + sh->a_out_buffer_len, filter_output->audio,
+ filter_output->len);
+ sh->a_out_buffer_len += filter_output->len;
// remove processed data from decoder buffer:
- sh_audio->a_buffer_len -= declen;
- if (sh_audio->a_buffer_len > 0)
- memmove(sh_audio->a_buffer, sh_audio->a_buffer + declen,
- sh_audio->a_buffer_len);
+ sh->a_buffer_len -= len;
+ memmove(sh->a_buffer, sh->a_buffer + len, sh->a_buffer_len);
- return maxlen;
+ return error;
+}
+
+/* Try to get at least minlen decoded+filtered bytes in sh_audio->a_out_buffer
+ * (total length including possible existing data).
+ * Return 0 on success, -1 on error/EOF (not distinguished).
+ * In the former case sh_audio->a_out_buffer_len is always >= minlen
+ * on return. In case of EOF/error it might or might not be.
+ * Can reallocate sh_audio->a_out_buffer if needed to fit all filter output. */
+int decode_audio(sh_audio_t *sh_audio, int minlen)
+{
+ if (!sh_audio->inited || !sh_audio->afilter)
+ abort();
+
+ // Decoded audio must be cut at boundaries of this many bytes
+ int unitsize = sh_audio->channels * sh_audio->samplesize;
+
+ /* Filter output size will be about filter_multiplier times input size.
+ * If some filter buffers audio in big blocks this might only hold
+ * as average over time. */
+ double filter_multiplier = af_calc_filter_multiplier(sh_audio->afilter);
+
+ /* If the decoder set audio_out_minsize then it can do the equivalent of
+ * "while (output_len < target_len) output_len += audio_out_minsize;",
+ * so we must guarantee there is at least audio_out_minsize-1 bytes
+ * more space in the output buffer than the minimum length we try to
+ * decode. */
+ int max_decode_len = sh_audio->a_buffer_size - sh_audio->audio_out_minsize;
+ max_decode_len -= max_decode_len % unitsize;
+
+ while (sh_audio->a_out_buffer_len < minlen) {
+ int declen = (minlen - sh_audio->a_out_buffer_len) / filter_multiplier
+ + (unitsize << 5); // some extra for possible filter buffering
+ if (declen > max_decode_len) { // Do it in several steps
+ if (filter_n_bytes(sh_audio, max_decode_len) < 0)
+ return -1;
+ continue;
+ }
+ declen -= declen % unitsize;
+ if (filter_n_bytes(sh_audio, declen) < 0)
+ return -1;
+ if (sh_audio->a_out_buffer_len >= minlen)
+ return 0;
+ /* Some filter must be doing significant buffering if the estimated
+ * input length didn't produce enough output from filters.
+ * Feed the filters 2k bytes at a time until we have enough output.
+ * Very small amounts could make filtering inefficient while large
+ * amounts can make MPlayer demux the file unnecessarily far ahead
+ * to get audio data and buffer video frames in memory while doing
+ * so. However the performance impact of either is probably not too
+ * significant as long as the value is not completely insane. */
+ declen = min(2000, max_decode_len);
+ declen -= declen % unitsize;
+ while (sh_audio->a_out_buffer_len < minlen) {
+ if (filter_n_bytes(sh_audio, declen) < 0)
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
}
void resync_audio_stream(sh_audio_t *sh_audio)
diff --git a/libmpcodecs/dec_audio.h b/libmpcodecs/dec_audio.h
index d372a65fc8..e5d71b8792 100644
--- a/libmpcodecs/dec_audio.h
+++ b/libmpcodecs/dec_audio.h
@@ -2,7 +2,7 @@
// dec_audio.c:
extern void afm_help(void);
extern int init_best_audio_codec(sh_audio_t *sh_audio,char** audio_codec_list,char** audio_fm_list);
-extern int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen);
+extern int decode_audio(sh_audio_t *sh_audio, int minlen);
extern void resync_audio_stream(sh_audio_t *sh_audio);
extern void skip_audio_frame(sh_audio_t *sh_audio);
extern void uninit_audio(sh_audio_t *sh_audio);
diff --git a/mencoder.c b/mencoder.c
index 9ef7835c8f..219f3ff79c 100644
--- a/mencoder.c
+++ b/mencoder.c
@@ -337,14 +337,7 @@ static int dec_audio(sh_audio_t *sh_audio,unsigned char* buffer,int total){
while(size<total && !at_eof){
int len=total-size;
if(len>MAX_OUTBURST) len=MAX_OUTBURST;
- if(len>sh_audio->a_out_buffer_size) len=sh_audio->a_out_buffer_size;
- if(len>sh_audio->a_out_buffer_len){
- int ret=decode_audio(sh_audio,
- &sh_audio->a_out_buffer[sh_audio->a_out_buffer_len],
- len-sh_audio->a_out_buffer_len,
- sh_audio->a_out_buffer_size-sh_audio->a_out_buffer_len);
- if(ret>0) sh_audio->a_out_buffer_len+=ret; else at_eof=1;
- }
+ if (decode_audio(sh_audio, len) < 0) at_eof=1;
if(len>sh_audio->a_out_buffer_len) len=sh_audio->a_out_buffer_len;
fast_memcpy(buffer+size,sh_audio->a_out_buffer,len);
sh_audio->a_out_buffer_len-=len; size+=len;
diff --git a/mplayer.c b/mplayer.c
index 9b7c87ba64..205864a254 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -1779,22 +1779,12 @@ static int fill_audio_out_buffers(void)
// Fill buffer if needed:
current_module="decode_audio";
t = GetTimer();
- while (sh_audio->a_out_buffer_len < playsize) {
- int buflen = sh_audio->a_out_buffer_len;
- int ret = decode_audio(sh_audio, &sh_audio->a_out_buffer[buflen],
- playsize - buflen, // min bytes
- sh_audio->a_out_buffer_size - buflen // max
- );
- if (ret <= 0) { // EOF?
- if (mpctx->d_audio->eof) {
- audio_eof = 1;
- if (sh_audio->a_out_buffer_len == 0)
- return 0;
- }
- break;
+ if (decode_audio(sh_audio, playsize) < 0) // EOF or error
+ if (mpctx->d_audio->eof) {
+ audio_eof = 1;
+ if (sh_audio->a_out_buffer_len == 0)
+ return 0;
}
- sh_audio->a_out_buffer_len += ret;
- }
t = GetTimer() - t;
tt = t*0.000001f; audio_time_usage+=tt;
if (playsize > sh_audio->a_out_buffer_len) {