summaryrefslogtreecommitdiffstats
path: root/libmpcodecs
diff options
context:
space:
mode:
authorreimar <reimar@b3059339-0415-0410-9bf9-f77b7e298cf2>2010-07-15 17:59:46 +0000
committerUoti Urpala <uau@glyph.nonexistent.invalid>2010-11-02 04:14:44 +0200
commit5ed772b9cddc4c0de6762e223428b3e36eceefff (patch)
tree338d1623dd003d777b17c3c64c90049b4c9ebd2c /libmpcodecs
parent6be6ba40946d333e9d2cf741ba401366e9081c79 (diff)
downloadmpv-5ed772b9cddc4c0de6762e223428b3e36eceefff.tar.bz2
mpv-5ed772b9cddc4c0de6762e223428b3e36eceefff.tar.xz
audio: support parameter changes (e.g. channel count) during playback
Add support for parameter changes (e.g. channel count) during playback. This makes decoding AC3 files that switch between 2 and 6 channels work reasonably well even with -channels 6 and ffac3 decoder. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@31737 b3059339-0415-0410-9bf9-f77b7e298cf2 Fix typo in error message: ACC -> AAC git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@32473 b3059339-0415-0410-9bf9-f77b7e298cf2 Avoid printing AAC with SBR warning on every decode call, instead print it only after every decoder reconfiguration. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@32476 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpcodecs')
-rw-r--r--libmpcodecs/ad_ffmpeg.c70
-rw-r--r--libmpcodecs/dec_audio.c16
2 files changed, 61 insertions, 25 deletions
diff --git a/libmpcodecs/ad_ffmpeg.c b/libmpcodecs/ad_ffmpeg.c
index 8578314bc6..6d27a314f6 100644
--- a/libmpcodecs/ad_ffmpeg.c
+++ b/libmpcodecs/ad_ffmpeg.c
@@ -52,6 +52,44 @@ static int preinit(sh_audio_t *sh)
return 1;
}
+static int setup_format(sh_audio_t *sh_audio, const AVCodecContext *lavc_context)
+{
+ int broken_srate = 0;
+ int samplerate = lavc_context->sample_rate;
+ int sample_format = sh_audio->sample_format;
+ switch (lavc_context->sample_fmt) {
+ case SAMPLE_FMT_U8: sample_format = AF_FORMAT_U8; break;
+ case SAMPLE_FMT_S16: sample_format = AF_FORMAT_S16_NE; break;
+ case SAMPLE_FMT_S32: sample_format = AF_FORMAT_S32_NE; break;
+ case SAMPLE_FMT_FLT: sample_format = AF_FORMAT_FLOAT_NE; break;
+ default:
+ mp_msg(MSGT_DECAUDIO, MSGL_FATAL, "Unsupported sample format\n");
+ }
+ if(sh_audio->wf){
+ // If the decoder uses the wrong number of channels all is lost anyway.
+ // sh_audio->channels=sh_audio->wf->nChannels;
+
+ if (lavc_context->codec_id == CODEC_ID_AAC &&
+ samplerate == 2*sh_audio->wf->nSamplesPerSec) {
+ broken_srate = 1;
+ } else if (sh_audio->wf->nSamplesPerSec)
+ samplerate=sh_audio->wf->nSamplesPerSec;
+ }
+ if (lavc_context->channels != sh_audio->channels ||
+ samplerate != sh_audio->samplerate ||
+ sample_format != sh_audio->sample_format) {
+ sh_audio->channels=lavc_context->channels;
+ sh_audio->samplerate=samplerate;
+ sh_audio->sample_format = sample_format;
+ sh_audio->samplesize=af_fmt2bits(sh_audio->sample_format)/ 8;
+ if (broken_srate)
+ mp_msg(MSGT_DECAUDIO, MSGL_WARN,
+ "Ignoring broken container sample rate for AAC with SBR\n");
+ return 1;
+ }
+ return 0;
+}
+
static int init(sh_audio_t *sh_audio)
{
struct MPOpts *opts = sh_audio->opts;
@@ -133,32 +171,19 @@ static int init(sh_audio_t *sh_audio)
} while (x <= 0 && tries++ < 5);
if(x>0) sh_audio->a_buffer_len=x;
- sh_audio->channels=lavc_context->channels;
- sh_audio->samplerate=lavc_context->sample_rate;
sh_audio->i_bps=lavc_context->bit_rate/8;
+ if (sh_audio->wf && sh_audio->wf->nAvgBytesPerSec)
+ sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec;
+
switch (lavc_context->sample_fmt) {
- case SAMPLE_FMT_U8: sh_audio->sample_format = AF_FORMAT_U8; break;
- case SAMPLE_FMT_S16: sh_audio->sample_format = AF_FORMAT_S16_NE; break;
- case SAMPLE_FMT_S32: sh_audio->sample_format = AF_FORMAT_S32_NE; break;
- case SAMPLE_FMT_FLT: sh_audio->sample_format = AF_FORMAT_FLOAT_NE; break;
+ case SAMPLE_FMT_U8:
+ case SAMPLE_FMT_S16:
+ case SAMPLE_FMT_S32:
+ case SAMPLE_FMT_FLT:
+ break;
default:
- mp_msg(MSGT_DECAUDIO, MSGL_FATAL, "Unsupported sample format\n");
return 0;
}
- /* If the audio is AAC the container level data may be unreliable
- * because of SBR handling problems (possibly half real sample rate at
- * container level). Default AAC decoding with ad_faad has used codec-level
- * values for a long time without generating complaints so it should be OK.
- */
- if (sh_audio->wf && lavc_context->codec_id != CODEC_ID_AAC) {
- // If the decoder uses the wrong number of channels all is lost anyway.
- // sh_audio->channels=sh_audio->wf->nChannels;
- if (sh_audio->wf->nSamplesPerSec)
- sh_audio->samplerate=sh_audio->wf->nSamplesPerSec;
- if (sh_audio->wf->nAvgBytesPerSec)
- sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec;
- }
- sh_audio->samplesize=af_fmt2bits(sh_audio->sample_format)/ 8;
return 1;
}
@@ -232,6 +257,9 @@ static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int m
sh_audio->pts_bytes += len2;
}
mp_dbg(MSGT_DECAUDIO,MSGL_DBG2,"Decoded %d -> %d \n",y,len2);
+
+ if (setup_format(sh_audio, sh_audio->context))
+ break;
}
return len;
}
diff --git a/libmpcodecs/dec_audio.c b/libmpcodecs/dec_audio.c
index 218203272d..ade2429dc0 100644
--- a/libmpcodecs/dec_audio.c
+++ b/libmpcodecs/dec_audio.c
@@ -378,13 +378,20 @@ static int filter_n_bytes(sh_audio_t *sh, int len)
int error = 0;
// Decode more bytes if needed
+ int old_samplerate = sh->samplerate;
+ int old_channels = sh->channels;
+ int old_sample_format = sh->sample_format;
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;
+ int format_change = sh->samplerate != old_samplerate
+ || sh->channels != old_channels
+ || sh->sample_format != old_sample_format;
+ if (ret <= 0 || format_change) {
+ error = format_change ? -2 : -1;
+ // samples from format-changing call get discarded too
len = sh->a_buffer_len;
break;
}
@@ -467,8 +474,9 @@ int decode_audio(sh_audio_t *sh_audio, int minlen)
/* if this iteration does not fill buffer, we must have lots
* of buffering in filters */
huge_filter_buffer = 1;
- if (filter_n_bytes(sh_audio, declen) < 0)
- return -1;
+ int res = filter_n_bytes(sh_audio, declen);
+ if (res < 0)
+ return res;
}
return 0;
}