Skip to content

Commit 676ffab

Browse files
committed
Add adaptive bitrate streaming support to video_player_avfoundation
Implements setBandwidthLimit via AVPlayerItem.preferredPeakBitRate. A value of 0 removes the bandwidth cap, letting AVFoundation select quality freely. Positive values limit the peak bitrate in bps. Requires video_player_platform_interface ^6.7.0. Part of flutter/flutter#183941
1 parent 8dcfd11 commit 676ffab

File tree

10 files changed

+299
-232
lines changed

10 files changed

+299
-232
lines changed

packages/video_player/video_player_avfoundation/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.10.0
2+
3+
* Adds `setBandwidthLimit` for adaptive bitrate streaming via `preferredPeakBitRate`.
4+
15
## 2.9.4
26

37
* Ensures that the display link does not continue requesting frames after a player is disposed.

packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,22 @@ - (void)selectAudioTrackAtIndex:(NSInteger)trackIndex
508508
}
509509
}
510510

511+
- (void)setBandwidthLimit:(NSInteger)maxBandwidthBps
512+
error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
513+
AVPlayerItem *currentItem = _player.currentItem;
514+
NSAssert(currentItem, @"currentItem should not be nil");
515+
516+
if (maxBandwidthBps <= 0) {
517+
// A value of 0 tells AVFoundation to use its default limit, effectively
518+
// removing any cap and letting the player choose quality freely.
519+
currentItem.preferredPeakBitRate = 0;
520+
} else {
521+
// AVPlayer will attempt to select HLS variant streams at or below this
522+
// bitrate. The actual bitrate depends on available variants.
523+
currentItem.preferredPeakBitRate = (double)maxBandwidthBps;
524+
}
525+
}
526+
511527
#pragma mark - Private
512528

513529
- (int64_t)duration {

packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,41 +22,42 @@ NS_ASSUME_NONNULL_BEGIN
2222
@interface FVPPlatformVideoViewCreationParams : NSObject
2323
/// `init` unavailable to enforce nonnull fields, see the `make` class method.
2424
- (instancetype)init NS_UNAVAILABLE;
25-
+ (instancetype)makeWithPlayerId:(NSInteger)playerId;
26-
@property(nonatomic, assign) NSInteger playerId;
25+
+ (instancetype)makeWithPlayerId:(NSInteger )playerId;
26+
@property(nonatomic, assign) NSInteger playerId;
2727
@end
2828

2929
@interface FVPCreationOptions : NSObject
3030
/// `init` unavailable to enforce nonnull fields, see the `make` class method.
3131
- (instancetype)init NS_UNAVAILABLE;
3232
+ (instancetype)makeWithUri:(NSString *)uri
33-
httpHeaders:(NSDictionary<NSString *, NSString *> *)httpHeaders;
34-
@property(nonatomic, copy) NSString *uri;
35-
@property(nonatomic, copy) NSDictionary<NSString *, NSString *> *httpHeaders;
33+
httpHeaders:(NSDictionary<NSString *, NSString *> *)httpHeaders;
34+
@property(nonatomic, copy) NSString * uri;
35+
@property(nonatomic, copy) NSDictionary<NSString *, NSString *> * httpHeaders;
3636
@end
3737

3838
@interface FVPTexturePlayerIds : NSObject
3939
/// `init` unavailable to enforce nonnull fields, see the `make` class method.
4040
- (instancetype)init NS_UNAVAILABLE;
41-
+ (instancetype)makeWithPlayerId:(NSInteger)playerId textureId:(NSInteger)textureId;
42-
@property(nonatomic, assign) NSInteger playerId;
43-
@property(nonatomic, assign) NSInteger textureId;
41+
+ (instancetype)makeWithPlayerId:(NSInteger )playerId
42+
textureId:(NSInteger )textureId;
43+
@property(nonatomic, assign) NSInteger playerId;
44+
@property(nonatomic, assign) NSInteger textureId;
4445
@end
4546

4647
/// Raw audio track data from AVMediaSelectionOption (for HLS streams).
4748
@interface FVPMediaSelectionAudioTrackData : NSObject
4849
/// `init` unavailable to enforce nonnull fields, see the `make` class method.
4950
- (instancetype)init NS_UNAVAILABLE;
50-
+ (instancetype)makeWithIndex:(NSInteger)index
51-
displayName:(nullable NSString *)displayName
52-
languageCode:(nullable NSString *)languageCode
53-
isSelected:(BOOL)isSelected
54-
commonMetadataTitle:(nullable NSString *)commonMetadataTitle;
55-
@property(nonatomic, assign) NSInteger index;
56-
@property(nonatomic, copy, nullable) NSString *displayName;
57-
@property(nonatomic, copy, nullable) NSString *languageCode;
58-
@property(nonatomic, assign) BOOL isSelected;
59-
@property(nonatomic, copy, nullable) NSString *commonMetadataTitle;
51+
+ (instancetype)makeWithIndex:(NSInteger )index
52+
displayName:(nullable NSString *)displayName
53+
languageCode:(nullable NSString *)languageCode
54+
isSelected:(BOOL )isSelected
55+
commonMetadataTitle:(nullable NSString *)commonMetadataTitle;
56+
@property(nonatomic, assign) NSInteger index;
57+
@property(nonatomic, copy, nullable) NSString * displayName;
58+
@property(nonatomic, copy, nullable) NSString * languageCode;
59+
@property(nonatomic, assign) BOOL isSelected;
60+
@property(nonatomic, copy, nullable) NSString * commonMetadataTitle;
6061
@end
6162

6263
/// The codec used by all APIs.
@@ -65,25 +66,17 @@ NSObject<FlutterMessageCodec> *FVPGetMessagesCodec(void);
6566
@protocol FVPAVFoundationVideoPlayerApi
6667
- (void)initialize:(FlutterError *_Nullable *_Nonnull)error;
6768
/// @return `nil` only when `error != nil`.
68-
- (nullable NSNumber *)createPlatformViewPlayerWithOptions:(FVPCreationOptions *)params
69-
error:(FlutterError *_Nullable *_Nonnull)error;
69+
- (nullable NSNumber *)createPlatformViewPlayerWithOptions:(FVPCreationOptions *)params error:(FlutterError *_Nullable *_Nonnull)error;
7070
/// @return `nil` only when `error != nil`.
71-
- (nullable FVPTexturePlayerIds *)
72-
createTexturePlayerWithOptions:(FVPCreationOptions *)creationOptions
73-
error:(FlutterError *_Nullable *_Nonnull)error;
71+
- (nullable FVPTexturePlayerIds *)createTexturePlayerWithOptions:(FVPCreationOptions *)creationOptions error:(FlutterError *_Nullable *_Nonnull)error;
7472
- (void)setMixWithOthers:(BOOL)mixWithOthers error:(FlutterError *_Nullable *_Nonnull)error;
75-
- (nullable NSString *)fileURLForAssetWithName:(NSString *)asset
76-
package:(nullable NSString *)package
77-
error:(FlutterError *_Nullable *_Nonnull)error;
73+
- (nullable NSString *)fileURLForAssetWithName:(NSString *)asset package:(nullable NSString *)package error:(FlutterError *_Nullable *_Nonnull)error;
7874
@end
7975

80-
extern void SetUpFVPAVFoundationVideoPlayerApi(
81-
id<FlutterBinaryMessenger> binaryMessenger,
82-
NSObject<FVPAVFoundationVideoPlayerApi> *_Nullable api);
76+
extern void SetUpFVPAVFoundationVideoPlayerApi(id<FlutterBinaryMessenger> binaryMessenger, NSObject<FVPAVFoundationVideoPlayerApi> *_Nullable api);
77+
78+
extern void SetUpFVPAVFoundationVideoPlayerApiWithSuffix(id<FlutterBinaryMessenger> binaryMessenger, NSObject<FVPAVFoundationVideoPlayerApi> *_Nullable api, NSString *messageChannelSuffix);
8379

84-
extern void SetUpFVPAVFoundationVideoPlayerApiWithSuffix(
85-
id<FlutterBinaryMessenger> binaryMessenger,
86-
NSObject<FVPAVFoundationVideoPlayerApi> *_Nullable api, NSString *messageChannelSuffix);
8780

8881
@protocol FVPVideoPlayerInstanceApi
8982
- (void)setLooping:(BOOL)looping error:(FlutterError *_Nullable *_Nonnull)error;
@@ -96,17 +89,23 @@ extern void SetUpFVPAVFoundationVideoPlayerApiWithSuffix(
9689
- (void)pauseWithError:(FlutterError *_Nullable *_Nonnull)error;
9790
- (void)disposeWithError:(FlutterError *_Nullable *_Nonnull)error;
9891
/// @return `nil` only when `error != nil`.
99-
- (nullable NSArray<FVPMediaSelectionAudioTrackData *> *)getAudioTracks:
100-
(FlutterError *_Nullable *_Nonnull)error;
101-
- (void)selectAudioTrackAtIndex:(NSInteger)trackIndex
102-
error:(FlutterError *_Nullable *_Nonnull)error;
92+
- (nullable NSArray<FVPMediaSelectionAudioTrackData *> *)getAudioTracks:(FlutterError *_Nullable *_Nonnull)error;
93+
- (void)selectAudioTrackAtIndex:(NSInteger)trackIndex error:(FlutterError *_Nullable *_Nonnull)error;
94+
/// Sets the maximum bandwidth limit in bits per second for HLS adaptive bitrate streaming.
95+
/// Pass 0 to remove any bandwidth limit and allow the player to select quality freely.
96+
/// Common values:
97+
/// - 360p: 500000 bps (500 kbps)
98+
/// - 480p: 800000 bps (800 kbps)
99+
/// - 720p: 1200000 bps (1.2 Mbps)
100+
/// - 1080p: 2500000 bps (2.5 Mbps)
101+
///
102+
/// Note: On iOS/macOS, this sets the preferredPeakBitRate on AVPlayerItem,
103+
/// which influences AVPlayer's HLS variant selection.
104+
- (void)setBandwidthLimit:(NSInteger)maxBandwidthBps error:(FlutterError *_Nullable *_Nonnull)error;
103105
@end
104106

105-
extern void SetUpFVPVideoPlayerInstanceApi(id<FlutterBinaryMessenger> binaryMessenger,
106-
NSObject<FVPVideoPlayerInstanceApi> *_Nullable api);
107+
extern void SetUpFVPVideoPlayerInstanceApi(id<FlutterBinaryMessenger> binaryMessenger, NSObject<FVPVideoPlayerInstanceApi> *_Nullable api);
107108

108-
extern void SetUpFVPVideoPlayerInstanceApiWithSuffix(
109-
id<FlutterBinaryMessenger> binaryMessenger, NSObject<FVPVideoPlayerInstanceApi> *_Nullable api,
110-
NSString *messageChannelSuffix);
109+
extern void SetUpFVPVideoPlayerInstanceApiWithSuffix(id<FlutterBinaryMessenger> binaryMessenger, NSObject<FVPVideoPlayerInstanceApi> *_Nullable api, NSString *messageChannelSuffix);
111110

112111
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)