feat(android): initial bitrate (#4480)

* feat(android): implement initialBitrate

* refactor: reorder type

* docs: add initialBitrate section

* fix: lint

* refactor: move `initialBitrate` into `source.bufferConfig`
This commit is contained in:
Kamil Moskała
2025-04-06 16:16:58 +02:00
committed by GitHub
parent d2e5d9c64e
commit 41ddc5c27a
7 changed files with 43 additions and 15 deletions

View File

@@ -20,6 +20,7 @@ class BufferConfig {
var maxHeapAllocationPercent = BufferConfigPropUnsetDouble var maxHeapAllocationPercent = BufferConfigPropUnsetDouble
var minBackBufferMemoryReservePercent = BufferConfigPropUnsetDouble var minBackBufferMemoryReservePercent = BufferConfigPropUnsetDouble
var minBufferMemoryReservePercent = BufferConfigPropUnsetDouble var minBufferMemoryReservePercent = BufferConfigPropUnsetDouble
var initialBitrate = BufferConfigPropUnsetInt
var live: Live = Live() var live: Live = Live()
@@ -36,6 +37,7 @@ class BufferConfig {
maxHeapAllocationPercent == other.maxHeapAllocationPercent && maxHeapAllocationPercent == other.maxHeapAllocationPercent &&
minBackBufferMemoryReservePercent == other.minBackBufferMemoryReservePercent && minBackBufferMemoryReservePercent == other.minBackBufferMemoryReservePercent &&
minBufferMemoryReservePercent == other.minBufferMemoryReservePercent && minBufferMemoryReservePercent == other.minBufferMemoryReservePercent &&
initialBitrate == other.initialBitrate &&
live == other.live live == other.live
) )
} }
@@ -91,6 +93,7 @@ class BufferConfig {
private const val PROP_BUFFER_CONFIG_MIN_BACK_BUFFER_MEMORY_RESERVE_PERCENT = "minBackBufferMemoryReservePercent" private const val PROP_BUFFER_CONFIG_MIN_BACK_BUFFER_MEMORY_RESERVE_PERCENT = "minBackBufferMemoryReservePercent"
private const val PROP_BUFFER_CONFIG_MIN_BUFFER_MEMORY_RESERVE_PERCENT = "minBufferMemoryReservePercent" private const val PROP_BUFFER_CONFIG_MIN_BUFFER_MEMORY_RESERVE_PERCENT = "minBufferMemoryReservePercent"
private const val PROP_BUFFER_CONFIG_BACK_BUFFER_DURATION_MS = "backBufferDurationMs" private const val PROP_BUFFER_CONFIG_BACK_BUFFER_DURATION_MS = "backBufferDurationMs"
private const val PROP_BUFFER_CONFIG_INITIAL_BITRATE = "initialBitrate"
private const val PROP_BUFFER_CONFIG_LIVE = "live" private const val PROP_BUFFER_CONFIG_LIVE = "live"
@JvmStatic @JvmStatic
@@ -118,6 +121,7 @@ class BufferConfig {
BufferConfigPropUnsetDouble BufferConfigPropUnsetDouble
) )
bufferConfig.backBufferDurationMs = safeGetInt(src, PROP_BUFFER_CONFIG_BACK_BUFFER_DURATION_MS, BufferConfigPropUnsetInt) bufferConfig.backBufferDurationMs = safeGetInt(src, PROP_BUFFER_CONFIG_BACK_BUFFER_DURATION_MS, BufferConfigPropUnsetInt)
bufferConfig.initialBitrate = safeGetInt(src, PROP_BUFFER_CONFIG_INITIAL_BITRATE, BufferConfigPropUnsetInt)
bufferConfig.live = Live.parse(src.getMap(PROP_BUFFER_CONFIG_LIVE)) bufferConfig.live = Live.parse(src.getMap(PROP_BUFFER_CONFIG_LIVE))
} }
return bufferConfig return bufferConfig

View File

@@ -5,13 +5,26 @@ import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter
import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy
class DefaultReactExoplayerConfig(context: Context) : ReactExoplayerConfig { class DefaultReactExoplayerConfig(private val context: Context, override var initialBitrate: Long? = null) : ReactExoplayerConfig {
private var bandWidthMeter: DefaultBandwidthMeter = createBandwidthMeter(initialBitrate)
private var bandWidthMeter: DefaultBandwidthMeter = DefaultBandwidthMeter.Builder(context).build()
override var disableDisconnectError: Boolean = false override var disableDisconnectError: Boolean = false
override val bandwidthMeter: DefaultBandwidthMeter override val bandwidthMeter: DefaultBandwidthMeter
get() = bandWidthMeter get() = bandWidthMeter
private fun createBandwidthMeter(bitrate: Long?): DefaultBandwidthMeter =
DefaultBandwidthMeter.Builder(context)
.setInitialBitrateEstimate(bitrate ?: DefaultBandwidthMeter.DEFAULT_INITIAL_BITRATE_ESTIMATE)
.build()
override fun setInitialBitrate(bitrate: Long) {
if (initialBitrate == bitrate) return
initialBitrate = bitrate
bandWidthMeter = createBandwidthMeter(bitrate)
}
override fun buildLoadErrorHandlingPolicy(minLoadRetryCount: Int): LoadErrorHandlingPolicy = override fun buildLoadErrorHandlingPolicy(minLoadRetryCount: Int): LoadErrorHandlingPolicy =
if (disableDisconnectError) { if (disableDisconnectError) {
ReactExoplayerLoadErrorHandlingPolicy(minLoadRetryCount) ReactExoplayerLoadErrorHandlingPolicy(minLoadRetryCount)

View File

@@ -7,4 +7,6 @@ interface ReactExoplayerConfig {
fun buildLoadErrorHandlingPolicy(minLoadRetryCount: Int): LoadErrorHandlingPolicy fun buildLoadErrorHandlingPolicy(minLoadRetryCount: Int): LoadErrorHandlingPolicy
var disableDisconnectError: Boolean var disableDisconnectError: Boolean
val bandwidthMeter: DefaultBandwidthMeter val bandwidthMeter: DefaultBandwidthMeter
var initialBitrate: Long?
fun setInitialBitrate(bitrate: Long)
} }

View File

@@ -177,7 +177,7 @@ public class ReactExoplayerView extends FrameLayout implements
protected final VideoEventEmitter eventEmitter; protected final VideoEventEmitter eventEmitter;
private final ReactExoplayerConfig config; private final ReactExoplayerConfig config;
private final DefaultBandwidthMeter bandwidthMeter; private DefaultBandwidthMeter bandwidthMeter;
private LegacyPlayerControlView playerControlView; private LegacyPlayerControlView playerControlView;
private View playPauseControlContainer; private View playPauseControlContainer;
private Player.Listener eventListener; private Player.Listener eventListener;
@@ -849,6 +849,13 @@ public class ReactExoplayerView extends FrameLayout implements
allocator, allocator,
source.getBufferConfig() source.getBufferConfig()
); );
long initialBitrate = source.getBufferConfig().getInitialBitrate();
if (initialBitrate > 0) {
config.setInitialBitrate(initialBitrate);
this.bandwidthMeter = config.getBandwidthMeter();
}
DefaultRenderersFactory renderersFactory = DefaultRenderersFactory renderersFactory =
new DefaultRenderersFactory(getContext()) new DefaultRenderersFactory(getContext())
.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF) .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF)

Binary file not shown.

View File

@@ -986,15 +986,16 @@ source={{
Adjust the buffer settings. This prop takes an object with one or more of the properties listed below. Adjust the buffer settings. This prop takes an object with one or more of the properties listed below.
| Property | Type | Description | | Property | Type | Description |
|-----------------------------------|--------|---------------------------------------------------------------------------------------------------------------------------| |----------------------------------|--------|------------------------------------------------------------------------------------------------------------------------------------------------|
| minBufferMs | number | Minimum duration of media that the player will attempt to buffer at all times, in milliseconds. | | minBufferMs | number | Minimum duration of media that the player will attempt to buffer at all times, in milliseconds. |
| maxBufferMs | number | Maximum duration of media that the player will attempt to buffer, in milliseconds. | | maxBufferMs | number | Maximum duration of media that the player will attempt to buffer, in milliseconds. |
| bufferForPlaybackMs | number | Duration of media that must be buffered for playback to start or resume following a user action, in milliseconds. | | bufferForPlaybackMs | number | Duration of media that must be buffered for playback to start or resume following a user action, in milliseconds. |
| bufferForPlaybackAfterRebufferMs | number | Duration of media that must be buffered for playback to resume after a rebuffer, in milliseconds. | | bufferForPlaybackAfterRebufferMs | number | Duration of media that must be buffered for playback to resume after a rebuffer, in milliseconds. |
| backBufferDurationMs | number | Duration of buffer to keep before the current position, allowing rewinding without rebuffering. | | backBufferDurationMs | number | Duration of buffer to keep before the current position, allowing rewinding without rebuffering. |
| maxHeapAllocationPercent | number | Percentage of available heap that the video can use to buffer, between 0 and 1. | | maxHeapAllocationPercent | number | Percentage of available heap that the video can use to buffer, between 0 and 1. |
| minBackBufferMemoryReservePercent | number | Percentage of available app memory at which during startup the back buffer will be disabled, between 0 and 1. | | minBackBufferMemoryReservePercent| number | Percentage of available app memory at which during startup the back buffer will be disabled, between 0 and 1. |
| minBufferMemoryReservePercent | number | Percentage of available app memory to keep in reserve, preventing buffer usage, between 0 and 1. | | minBufferMemoryReservePercent | number | Percentage of available app memory to keep in reserve, preventing buffer usage, between 0 and 1. |
| initialBitrate | number | Initial bitrate in bits per second (Android only). Defaults to 1_000_000. Used only at start, then ABR (Adaptive Bitrate Streaming) takes over.|
| cacheSizeMB | number | Cache size in MB, preventing new src requests and saving bandwidth while repeating videos, or 0 to disable. Android only. | | cacheSizeMB | number | Cache size in MB, preventing new src requests and saving bandwidth while repeating videos, or 0 to disable. Android only. |
| live | object | Object containing another config set for live playback configuration. | | live | object | Object containing another config set for live playback configuration. |

View File

@@ -145,6 +145,7 @@ export type BufferConfig = {
maxHeapAllocationPercent?: number; maxHeapAllocationPercent?: number;
minBackBufferMemoryReservePercent?: number; minBackBufferMemoryReservePercent?: number;
minBufferMemoryReservePercent?: number; minBufferMemoryReservePercent?: number;
initialBitrate?: number; // Android
cacheSizeMB?: number; cacheSizeMB?: number;
live?: BufferConfigLive; live?: BufferConfigLive;
}; };