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 39f9416934f..7db1b810184 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.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; @@ -299,10 +300,21 @@ public Player(@NonNull final PlayerService service, 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 668b48c306c..04470612e51 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 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 @@ */ 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 @@ protected void buildVideoRenderers(final Context context, 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 352e4cec120..49886f4a6c1 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 147c88938a9..1d790dc7654 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 7e903fff151..3ef2d443366 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" /> + +