[vlc-devel] [PATCH V2 5/8] aout: handle DTSHD->DTS fallback

Thomas Guillem thomas at gllm.fr
Mon Oct 7 15:46:23 CEST 2019


Use the DTSHD fourcc instead of the hacked "dtshd" variable.

The DTSHD -> DTS fallback is now handled in aout core, the same code path will
be used for EAC3 -> AC3 fallback. Therefore, aout modules don't have to handle
the DTSHD -> DTS fallback anymore. If a module can't handle DTSHD, it should
return an error and the DTS fourcc will be tried right after.
---
 modules/audio_filter/converter/tospdif.c | 13 +++++----
 modules/audio_output/audiotrack.c        | 34 ++++++++++--------------
 modules/audio_output/mmdevice.c          |  2 --
 modules/audio_output/wasapi.c            | 22 +--------------
 src/audio_output/aout_internal.h         | 11 ++++++++
 src/audio_output/dec.c                   | 15 ++++-------
 src/audio_output/output.c                | 30 ++++++++++++++++++++-
 7 files changed, 66 insertions(+), 61 deletions(-)

diff --git a/modules/audio_filter/converter/tospdif.c b/modules/audio_filter/converter/tospdif.c
index 60f3e66544..239deae26f 100644
--- a/modules/audio_filter/converter/tospdif.c
+++ b/modules/audio_filter/converter/tospdif.c
@@ -96,6 +96,7 @@ static bool is_big_endian( filter_t *p_filter, block_t *p_in_buf )
         case VLC_CODEC_TRUEHD:
             return true;
         case VLC_CODEC_DTS:
+        case VLC_CODEC_DTSHD:
             return p_in_buf->p_buffer[0] == 0x1F
                 || p_in_buf->p_buffer[0] == 0x7F;
         default:
@@ -569,14 +570,11 @@ static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
         case VLC_CODEC_TRUEHD:
             i_ret = write_buffer_truehd( p_filter, p_in_buf );
             break;
+        case VLC_CODEC_DTSHD:
+            i_ret = write_buffer_dtshd( p_filter, p_in_buf );
+            break;
         case VLC_CODEC_DTS:
-            /* if the fmt_out is configured for a higher rate than 48kHz
-             * (IEC958 rate), use the DTS-HD framing to pass the DTS Core and
-             * or DTS substreams (like DTS-HD MA). */
-            if( p_filter->fmt_out.audio.i_rate > 48000 )
-                i_ret = write_buffer_dtshd( p_filter, p_in_buf );
-            else
-                i_ret = write_buffer_dts( p_filter, p_in_buf );
+            i_ret = write_buffer_dts( p_filter, p_in_buf );
             break;
         default:
             vlc_assert_unreachable();
@@ -606,6 +604,7 @@ static int Open( vlc_object_t *p_this )
     filter_sys_t *p_sys;
 
     if( ( p_filter->fmt_in.audio.i_format != VLC_CODEC_DTS &&
+          p_filter->fmt_in.audio.i_format != VLC_CODEC_DTSHD &&
           p_filter->fmt_in.audio.i_format != VLC_CODEC_A52 &&
           p_filter->fmt_in.audio.i_format != VLC_CODEC_EAC3 &&
           p_filter->fmt_in.audio.i_format != VLC_CODEC_MLP &&
diff --git a/modules/audio_output/audiotrack.c b/modules/audio_output/audiotrack.c
index a5351c80e5..8b153e0ad0 100644
--- a/modules/audio_output/audiotrack.c
+++ b/modules/audio_output/audiotrack.c
@@ -1075,24 +1075,18 @@ AudioTrack_Create( JNIEnv *env, audio_output_t *p_aout,
 }
 
 static bool
-AudioTrack_HasEncoding( audio_output_t *p_aout, vlc_fourcc_t i_format,
-                        bool *p_dtshd )
+AudioTrack_HasEncoding( audio_output_t *p_aout, vlc_fourcc_t i_format )
 {
     aout_sys_t *p_sys = p_aout->sys;
 
 #define MATCH_ENCODING_FLAG(x) jfields.AudioFormat.has_##x && \
     ( p_sys->i_encoding_flags == 0 || p_sys->i_encoding_flags & (1 << jfields.AudioFormat.x) )
 
-    *p_dtshd = false;
     switch( i_format )
     {
+        case VLC_CODEC_DTSHD:
+            return MATCH_ENCODING_FLAG( ENCODING_DTS_HD );
         case VLC_CODEC_DTS:
-            if( MATCH_ENCODING_FLAG( ENCODING_DTS_HD )
-             && var_GetBool( p_aout, "dtshd" ) )
-            {
-                *p_dtshd = true;
-                return true;
-            }
             return MATCH_ENCODING_FLAG( ENCODING_DTS );
         case VLC_CODEC_A52:
             return MATCH_ENCODING_FLAG( ENCODING_AC3 );
@@ -1112,8 +1106,7 @@ StartPassthrough( JNIEnv *env, audio_output_t *p_aout )
     aout_sys_t *p_sys = p_aout->sys;
     int i_at_format;
 
-    bool b_dtshd;
-    if( !AudioTrack_HasEncoding( p_aout, p_sys->fmt.i_format, &b_dtshd ) )
+    if( !AudioTrack_HasEncoding( p_aout, p_sys->fmt.i_format ) )
         return VLC_EGENERIC;
 
     if( jfields.AudioFormat.has_ENCODING_IEC61937 )
@@ -1134,11 +1127,12 @@ StartPassthrough( JNIEnv *env, audio_output_t *p_aout )
             case VLC_CODEC_DTS:
                 p_sys->fmt.i_bytes_per_frame = 4;
                 p_sys->fmt.i_physical_channels = AOUT_CHANS_STEREO;
-                if( b_dtshd )
-                {
-                    p_sys->fmt.i_rate = 192000;
-                    p_sys->fmt.i_bytes_per_frame = 16;
-                }
+                break;
+            case VLC_CODEC_DTSHD:
+                p_sys->fmt.i_bytes_per_frame = 4;
+                p_sys->fmt.i_physical_channels = AOUT_CHANS_STEREO;
+                p_sys->fmt.i_rate = 192000;
+                p_sys->fmt.i_bytes_per_frame = 16;
                 break;
             case VLC_CODEC_EAC3:
                 p_sys->fmt.i_rate = 192000;
@@ -2190,15 +2184,15 @@ static int DeviceSelect(audio_output_t *p_aout, const char *p_id)
         if( at_dev == AT_DEV_ENCODED )
         {
             static const vlc_fourcc_t enc_fourccs[] = {
-                VLC_CODEC_DTS, VLC_CODEC_A52, VLC_CODEC_EAC3, VLC_CODEC_TRUEHD,
+                VLC_CODEC_DTS, VLC_CODEC_DTSHD, VLC_CODEC_A52, VLC_CODEC_EAC3,
+                VLC_CODEC_TRUEHD,
             };
             for( size_t i = 0;
                  i < sizeof( enc_fourccs ) / sizeof( enc_fourccs[0] ); ++i )
             {
-                bool b_dtshd;
-                if( AudioTrack_HasEncoding( p_aout, enc_fourccs[i], &b_dtshd ) )
+                if( AudioTrack_HasEncoding( p_aout, enc_fourccs[i] ) )
                     msg_Dbg( p_aout, "device has %4.4s passthrough support",
-                             b_dtshd ? "dtsh" : (const char *)&enc_fourccs[i] );
+                             (const char *)&enc_fourccs[i] );
             }
         }
     }
diff --git a/modules/audio_output/mmdevice.c b/modules/audio_output/mmdevice.c
index 07381c7ae2..bf1d2958bd 100644
--- a/modules/audio_output/mmdevice.c
+++ b/modules/audio_output/mmdevice.c
@@ -1119,8 +1119,6 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
             case MM_PASSTHROUGH_ENABLED:
                 if (b_hdmi)
                     return -1;
-                else if (fmt->i_format == VLC_CODEC_DTS)
-                    var_SetBool(aout, "dtshd", false );
                 /* falltrough */
             case MM_PASSTHROUGH_ENABLED_HD:
                 break;
diff --git a/modules/audio_output/wasapi.c b/modules/audio_output/wasapi.c
index 113d0df1e6..66cfee466c 100644
--- a/modules/audio_output/wasapi.c
+++ b/modules/audio_output/wasapi.c
@@ -362,7 +362,7 @@ static void vlc_HdmiToWave(WAVEFORMATEXTENSIBLE_IEC61937 *restrict wf_iec61937,
 
     switch (audio->i_format)
     {
-    case VLC_CODEC_DTS:
+    case VLC_CODEC_DTSHD:
         wf->SubFormat = _KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
         wf->Format.nChannels = 8;
         wf->dwChannelMask = KSAUDIO_SPEAKER_7POINT1;
@@ -591,17 +591,6 @@ static HRESULT Start(aout_stream_t *s, audio_sample_format_t *restrict pfmt,
     audio_sample_format_t fmt = *pfmt;
     bool b_spdif = AOUT_FMT_SPDIF(&fmt);
     bool b_hdmi = AOUT_FMT_HDMI(&fmt);
-    bool b_dtshd = false;
-
-    if (fmt.i_format == VLC_CODEC_DTS)
-    {
-        b_dtshd = var_GetBool(vlc_object_parent(s), "dtshd");
-        if (b_dtshd)
-        {
-            b_hdmi = true;
-            b_spdif = false;
-        }
-    }
 
     void *pv;
     HRESULT hr = aout_stream_Activate(s, &IID_IAudioClient, NULL, &pv);
@@ -662,15 +651,6 @@ static HRESULT Start(aout_stream_t *s, audio_sample_format_t *restrict pfmt,
 
     if (FAILED(hr))
     {
-        if (pfmt->i_format == VLC_CODEC_DTS && b_hdmi)
-        {
-            msg_Warn(s, "cannot negotiate DTS at 768khz IEC958 rate (HDMI), "
-                     "fallback to 48kHz (S/PDIF) (error 0x%lX)", hr);
-            IAudioClient_Release(sys->client);
-            free(sys);
-            var_SetBool(vlc_object_parent(s), "dtshd", false);
-            return Start(s, pfmt, sid);
-        }
         msg_Err(s, "cannot negotiate audio format (error 0x%lX)%s", hr,
                 hr == AUDCLNT_E_UNSUPPORTED_FORMAT
                 && fmt.i_format == VLC_CODEC_SPDIFL ?
diff --git a/src/audio_output/aout_internal.h b/src/audio_output/aout_internal.h
index adb242eef6..a94d086410 100644
--- a/src/audio_output/aout_internal.h
+++ b/src/audio_output/aout_internal.h
@@ -76,7 +76,18 @@ typedef struct
 
     int requested_stereo_mode; /**< Requested stereo mode set by the user */
 
+    /* Original input format and profile, won't change for the lifetime of a
+     * stream (between aout_DecNew() and aout_DecDelete()). */
+    int                   input_profile;
     audio_sample_format_t input_format;
+
+    /* Format used to configure the conversion filters. It is based on the
+     * input_format but its fourcc can be different when the module is handling
+     * codec passthrough. Indeed, in case of DTSHD->DTS or EAC3->AC3 fallback,
+     * the filter need to know which codec is handled by the output. */
+    audio_sample_format_t filter_format;
+
+    /* Output format used and modified by the module. */
     audio_sample_format_t mixer_format;
 
     aout_filters_cfg_t filters_cfg;
diff --git a/src/audio_output/dec.c b/src/audio_output/dec.c
index 07161bba2f..d89fedbf62 100644
--- a/src/audio_output/dec.c
+++ b/src/audio_output/dec.c
@@ -92,14 +92,9 @@ int aout_DecNew(audio_output_t *p_aout, const audio_sample_format_t *p_format,
     owner->volume = aout_volume_New (p_aout, p_replay_gain);
 
     atomic_store_explicit(&owner->restart, 0, memory_order_relaxed);
-    owner->input_format = *p_format;
+    owner->input_profile = profile;
+    owner->filter_format = owner->mixer_format = owner->input_format = *p_format;
 
-    /* TODO: 3.0 HACK: we need to put i_profile inside audio_format_t for 4.0
-     * */
-    if( owner->input_format.i_format == VLC_CODEC_DTS )
-        var_SetBool( p_aout, "dtshd", profile > 0 );
-
-    owner->mixer_format = owner->input_format;
     owner->sync.clock = clock;
 
     owner->filters_cfg = AOUT_FILTERS_CFG_INIT;
@@ -109,7 +104,7 @@ int aout_DecNew(audio_output_t *p_aout, const audio_sample_format_t *p_format,
 
     /* Create the audio filtering "input" pipeline */
     owner->filters = aout_FiltersNewWithClock(VLC_OBJECT(p_aout), clock,
-                                              &owner->input_format,
+                                              &owner->filter_format,
                                               &owner->mixer_format,
                                               &owner->filters_cfg);
     if (owner->filters == NULL)
@@ -167,7 +162,7 @@ static int aout_CheckReady (audio_output_t *aout)
             msg_Dbg (aout, "restarting output...");
             if (owner->mixer_format.i_format)
                 aout_OutputDelete (aout);
-            owner->mixer_format = owner->input_format;
+            owner->filter_format = owner->mixer_format = owner->input_format;
             owner->filters_cfg = AOUT_FILTERS_CFG_INIT;
             if (aout_OutputNew (aout))
                 owner->mixer_format.i_format = 0;
@@ -189,7 +184,7 @@ static int aout_CheckReady (audio_output_t *aout)
         {
             owner->filters = aout_FiltersNewWithClock(VLC_OBJECT(aout),
                                                       owner->sync.clock,
-                                                      &owner->input_format,
+                                                      &owner->filter_format,
                                                       &owner->mixer_format,
                                                       &owner->filters_cfg);
             if (owner->filters == NULL)
diff --git a/src/audio_output/output.c b/src/audio_output/output.c
index 327b6268ce..93eb56fe05 100644
--- a/src/audio_output/output.c
+++ b/src/audio_output/output.c
@@ -517,16 +517,22 @@ static void aout_PrepareStereoMode (audio_output_t *aout,
 
 /**
  * Starts an audio output stream.
+ * \param output_codec codec accepted by the module, it can be different than
+ * the codec from the mixer_format in case of DTSHD/DTS or EAC3/AC3 fallback
  * \warning The caller must NOT hold the audio output lock.
  */
 int aout_OutputNew (audio_output_t *aout)
 {
     aout_owner_t *owner = aout_owner (aout);
     audio_sample_format_t *fmt = &owner->mixer_format;
+    audio_sample_format_t *filter_fmt = &owner->filter_format;
     aout_filters_cfg_t *filters_cfg = &owner->filters_cfg;
 
     audio_channel_type_t input_chan_type = fmt->channel_type;
     unsigned i_nb_input_channels = fmt->i_channels;
+    vlc_fourcc_t formats[] = {
+        fmt->i_format, 0, 0
+    };
 
     /* Ideally, the audio filters would be created before the audio output,
      * and the ideal audio format would be the output of the filters chain.
@@ -561,11 +567,33 @@ int aout_OutputNew (audio_output_t *aout)
         aout_FormatPrepare (fmt);
         assert (aout_FormatNbChannels(fmt) > 0);
     }
+    else
+    {
+        switch (fmt->i_format)
+        {
+            case VLC_CODEC_DTS:
+                if (owner->input_profile > 0)
+                {
+                    assert(ARRAY_SIZE(formats) >= 3);
+                    /* DTSHD can be played as DTSHD or as DTS */
+                    formats[0] = VLC_CODEC_DTSHD;
+                    formats[1] = VLC_CODEC_DTS;
+                }
+                break;
+            default:
+                break;
+        }
+    }
 
     aout->current_sink_info.headphones = false;
 
     vlc_mutex_lock(&owner->lock);
-    int ret = aout->start(aout, fmt);
+    int ret = VLC_EGENERIC;
+    for (size_t i = 0; formats[i] != 0 && ret != VLC_SUCCESS; ++i)
+    {
+        filter_fmt->i_format = fmt->i_format = formats[i];
+        ret = aout->start(aout, fmt);
+    }
     assert(aout->flush && aout->play && aout->time_get && aout->pause);
     vlc_mutex_unlock(&owner->lock);
     if (ret)
-- 
2.20.1



More information about the vlc-devel mailing list