changeset 31671:4541f1921482

Add support for parameter changes (e.g. channel count) during playback. This makes decoding AAC files that switch between 2 and 6 channels work reasonably well even with -channels 6 and ffaac decoder.
author reimar
date Thu, 15 Jul 2010 17:59:46 +0000
parents 05a6d70df204
children 61eac0d05f20
files libmpcodecs/ad_ffmpeg.c libmpcodecs/dec_audio.c mplayer.c
diffstat 3 files changed, 75 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/libmpcodecs/ad_ffmpeg.c	Wed Jul 14 21:36:06 2010 +0000
+++ b/libmpcodecs/ad_ffmpeg.c	Thu Jul 15 17:59:46 2010 +0000
@@ -52,6 +52,41 @@
   return 1;
 }
 
+static int setup_format(sh_audio_t *sh_audio, const AVCodecContext *lavc_context)
+{
+    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) {
+            mp_msg(MSGT_DECAUDIO, MSGL_WARN,
+                   "Ignoring broken container sample rate for ACC with SBR\n");
+        } 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;
+        return 1;
+    }
+    return 0;
+}
+
 static int init(sh_audio_t *sh_audio)
 {
     int tries = 0;
@@ -132,33 +167,19 @@
    } 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(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 &&
-          sh_audio->samplerate == 2*sh_audio->wf->nSamplesPerSec) {
-          mp_msg(MSGT_DECAUDIO, MSGL_WARN,
-                 "Ignoring broken container sample rate for ACC with SBR\n");
-      } else 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 +253,9 @@
 	  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;
 }
--- a/libmpcodecs/dec_audio.c	Wed Jul 14 21:36:06 2010 +0000
+++ b/libmpcodecs/dec_audio.c	Thu Jul 15 17:59:46 2010 +0000
@@ -388,8 +388,11 @@
 	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 != filter_input.rate ||
+	                    sh->channels != filter_input.nch ||
+	                    sh->sample_format != filter_input.format;
+	if (ret <= 0 || format_change) {
+	    error = format_change ? -2 : -1;
 	    len = sh->a_buffer_len;
 	    break;
 	}
@@ -446,6 +449,7 @@
     max_decode_len -= max_decode_len % unitsize;
 
     while (sh_audio->a_out_buffer_len < minlen) {
+	int res;
 	int declen = (minlen - sh_audio->a_out_buffer_len) / filter_multiplier
 	    + (unitsize << 5); // some extra for possible filter buffering
 	if (huge_filter_buffer)
@@ -465,8 +469,9 @@
 	    /* 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;
+	res = filter_n_bytes(sh_audio, declen);
+	if (res < 0)
+	    return res;
     }
     return 0;
 }
--- a/mplayer.c	Wed Jul 14 21:36:06 2010 +0000
+++ b/mplayer.c	Thu Jul 15 17:59:46 2010 +0000
@@ -1652,6 +1652,7 @@
 void reinit_audio_chain(void) {
     if (!mpctx->sh_audio)
         return;
+    if (!(initialized_flags & INITIALIZED_ACODEC)) {
     current_module="init_audio_codec";
     mp_msg(MSGT_CPLAYER,MSGL_INFO,"==========================================================================\n");
     if(!init_best_audio_codec(mpctx->sh_audio,audio_codec_list,audio_fm_list)){
@@ -1659,8 +1660,10 @@
     }
     initialized_flags|=INITIALIZED_ACODEC;
     mp_msg(MSGT_CPLAYER,MSGL_INFO,"==========================================================================\n");
-
-
+    }
+
+
+    if (!(initialized_flags & INITIALIZED_AO)) {
     current_module="af_preinit";
     ao_data.samplerate=force_srate;
     ao_data.channels=0;
@@ -1694,6 +1697,8 @@
            mpctx->audio_out->info->name, mpctx->audio_out->info->author);
     if(strlen(mpctx->audio_out->info->comment) > 0)
         mp_msg(MSGT_CPLAYER,MSGL_V,"AO: Comment: %s\n", mpctx->audio_out->info->comment);
+    }
+
     // init audio filters:
     current_module="af_init";
     if(!build_afilter_chain(mpctx->sh_audio, &ao_data)) {
@@ -2120,6 +2125,7 @@
     int playflags=0;
     int audio_eof=0;
     int bytes_to_write;
+    int format_change = 0;
     sh_audio_t * const sh_audio = mpctx->sh_audio;
 
     current_module="play_audio";
@@ -2143,6 +2149,7 @@
     }
 
     while (bytes_to_write) {
+	int res;
 	playsize = bytes_to_write;
 	if (playsize > MAX_OUTBURST)
 	    playsize = MAX_OUTBURST;
@@ -2151,7 +2158,11 @@
 	// Fill buffer if needed:
 	current_module="decode_audio";
 	t = GetTimer();
-	if (decode_audio(sh_audio, playsize) < 0) // EOF or error
+	if (!format_change) {
+	    res = decode_audio(sh_audio, playsize);
+	    format_change = res == -2;
+	}
+	if (!format_change && res < 0) // EOF or error
 	    if (mpctx->d_audio->eof) {
 		audio_eof = 1;
 		if (sh_audio->a_out_buffer_len == 0)
@@ -2161,7 +2172,7 @@
 	tt = t*0.000001f; audio_time_usage+=tt;
 	if (playsize > sh_audio->a_out_buffer_len) {
 	    playsize = sh_audio->a_out_buffer_len;
-	    if (audio_eof)
+	    if (audio_eof || format_change)
 		playflags |= AOPLAY_FINAL_CHUNK;
 	}
 	if (!playsize)
@@ -2182,13 +2193,17 @@
 		    sh_audio->a_out_buffer_len);
 	    mpctx->delay += playback_speed*playsize/(double)ao_data.bps;
 	}
-	else if (audio_eof && mpctx->audio_out->get_delay() < .04) {
+	else if ((format_change || audio_eof) && mpctx->audio_out->get_delay() < .04) {
 	    // Sanity check to avoid hanging in case current ao doesn't output
 	    // partial chunks and doesn't check for AOPLAY_FINAL_CHUNK
 	    mp_msg(MSGT_CPLAYER, MSGL_WARN, "Audio output truncated at end.\n");
 	    sh_audio->a_out_buffer_len = 0;
 	}
     }
+    if (format_change) {
+	uninit_player(INITIALIZED_AO);
+	reinit_audio_chain();
+    }
     return 1;
 }