diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index b07b15a45..f909b0e44 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -73,6 +73,7 @@ import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Player.PositionInfo; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Tracks; +import com.google.android.exoplayer2.audio.SilenceSkippingAudioProcessor; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.text.CueGroup; @@ -301,10 +302,21 @@ public final class Player implements PlaybackListener, Listener { new DefaultBandwidthMeter.Builder(context).build()); loadController = new LoadController(); - renderFactory = prefs.getBoolean( - context.getString( - R.string.always_use_exoplayer_set_output_surface_workaround_key), false) - ? new CustomRenderersFactory(context) : new DefaultRenderersFactory(context); + final boolean alwaysUseExoplayerSetOutputSurfaceWorkaround = prefs.getBoolean( + context.getString(R.string.always_use_exoplayer_set_output_surface_workaround_key), + false); + final int maxSilenceDurationMillis = prefs.getInt( + context.getString(R.string.max_silence_duration_key), + Integer.parseInt(context.getString(R.string.max_silence_duration_value))); + final long maxSilenceDurationMicros = MILLISECONDS.toMicros(maxSilenceDurationMillis); + final SilenceSkippingAudioProcessor silenceSkippingAudioProcessor = + new SilenceSkippingAudioProcessor( + maxSilenceDurationMicros, + maxSilenceDurationMicros, + SilenceSkippingAudioProcessor.DEFAULT_SILENCE_THRESHOLD_LEVEL); + renderFactory = new CustomRenderersFactory( + context, alwaysUseExoplayerSetOutputSurfaceWorkaround, + silenceSkippingAudioProcessor); renderFactory.setEnableDecoderFallback( prefs.getBoolean( diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/CustomRenderersFactory.java b/app/src/main/java/org/schabi/newpipe/player/helper/CustomRenderersFactory.java index 668b48c30..04470612e 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/CustomRenderersFactory.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/CustomRenderersFactory.java @@ -5,14 +5,21 @@ import android.os.Handler; import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.Renderer; +import com.google.android.exoplayer2.audio.AudioCapabilities; +import com.google.android.exoplayer2.audio.AudioProcessor; +import com.google.android.exoplayer2.audio.AudioSink; +import com.google.android.exoplayer2.audio.DefaultAudioSink; +import com.google.android.exoplayer2.audio.SilenceSkippingAudioProcessor; +import com.google.android.exoplayer2.audio.SonicAudioProcessor; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.video.VideoRendererEventListener; import java.util.ArrayList; /** - * A {@link DefaultRenderersFactory} which only uses {@link CustomMediaCodecVideoRenderer} as an - * implementation of video codec renders. + * A {@link DefaultRenderersFactory} which uses {@link CustomMediaCodecVideoRenderer} as an + * implementation of video codec renders and uses a provided {@link SilenceSkippingAudioProcessor} + * to control silence skipping behavior more precisely. * *

* As no ExoPlayer extension is currently used, the reflection code used by ExoPlayer to try to @@ -22,8 +29,17 @@ import java.util.ArrayList; */ public final class CustomRenderersFactory extends DefaultRenderersFactory { - public CustomRenderersFactory(final Context context) { + private final boolean alwaysUseExoplayerSetOutputSurfaceWorkaround; + private final SilenceSkippingAudioProcessor silenceSkippingAudioProcessor; + + public CustomRenderersFactory( + final Context context, + final boolean alwaysUseExoplayerSetOutputSurfaceWorkaround, + final SilenceSkippingAudioProcessor silenceSkippingAudioProcessor) { super(context); + this.alwaysUseExoplayerSetOutputSurfaceWorkaround = + alwaysUseExoplayerSetOutputSurfaceWorkaround; + this.silenceSkippingAudioProcessor = silenceSkippingAudioProcessor; } @SuppressWarnings("checkstyle:ParameterNumber") @@ -36,8 +52,35 @@ public final class CustomRenderersFactory extends DefaultRenderersFactory { final VideoRendererEventListener eventListener, final long allowedVideoJoiningTimeMs, final ArrayList out) { - out.add(new CustomMediaCodecVideoRenderer(context, getCodecAdapterFactory(), - mediaCodecSelector, allowedVideoJoiningTimeMs, enableDecoderFallback, eventHandler, - eventListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)); + if (alwaysUseExoplayerSetOutputSurfaceWorkaround) { + out.add(new CustomMediaCodecVideoRenderer(context, getCodecAdapterFactory(), + mediaCodecSelector, allowedVideoJoiningTimeMs, enableDecoderFallback, + eventHandler, eventListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)); + } else { + super.buildVideoRenderers(context, extensionRendererMode, mediaCodecSelector, + enableDecoderFallback, eventHandler, eventListener, allowedVideoJoiningTimeMs, + out); + } + } + + @Override + protected AudioSink buildAudioSink( + final Context context, + final boolean enableFloatOutput, + final boolean enableAudioTrackPlaybackParams, + final boolean enableOffload) { + return new DefaultAudioSink.Builder() + .setAudioCapabilities(AudioCapabilities.getCapabilities(context)) + .setEnableFloatOutput(enableFloatOutput) + .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) + .setOffloadMode( + enableOffload + ? DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED + : DefaultAudioSink.OFFLOAD_MODE_DISABLED) + .setAudioProcessorChain(new DefaultAudioSink.DefaultAudioProcessorChain( + new AudioProcessor[]{}, silenceSkippingAudioProcessor, + new SonicAudioProcessor() + )) + .build(); } } diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index ab6e9e345..3cfe94ad0 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -123,6 +123,10 @@ default_popup_resolution 480p best_resolution + 500 + 100 + 5000 + max_silence_duration 2160p diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9095fe927..d6ee00f85 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -50,6 +50,7 @@ Default popup resolution Show higher resolutions Only some devices can play 2K/4K videos + Maximal silence duration in milliseconds that remains when \"fast forwarding during silence\" is enabled Play with Kodi Install missing Kore app\? Show \"Play with Kodi\" option diff --git a/app/src/main/res/xml/exoplayer_settings.xml b/app/src/main/res/xml/exoplayer_settings.xml index 7e903fff1..3ef2d4433 100644 --- a/app/src/main/res/xml/exoplayer_settings.xml +++ b/app/src/main/res/xml/exoplayer_settings.xml @@ -37,4 +37,15 @@ app:singleLineTitle="false" app:iconSpaceReserved="false" /> + +