Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

[video_player]add http headers option when loading network data source #953

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.Nullable;
import android.view.Surface;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
Expand All @@ -32,7 +33,9 @@
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory;
import com.google.android.exoplayer2.upstream.HttpDataSource.RequestProperties;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Util;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
Expand All @@ -51,6 +54,56 @@

public class VideoPlayerPlugin implements MethodCallHandler {

// near copy and paste from final class DefaultHttpDataSourceFactory
private static class VideoPlayerHttpDataSourceFactory extends BaseFactory {
private final String userAgent;
private final @Nullable TransferListener listener;
private final int connectTimeoutMillis;
private final int readTimeoutMillis;
private final boolean allowCrossProtocolRedirects;
private final Map<String, String> headers;

public VideoPlayerHttpDataSourceFactory(
String userAgent,
@Nullable TransferListener listener,
int connectTimeoutMillis,
int readTimeoutMillis,
boolean allowCrossProtocolRedirects,
Map<String, String> headers) {
this.userAgent = userAgent;
this.listener = listener;
this.connectTimeoutMillis = connectTimeoutMillis;
this.readTimeoutMillis = readTimeoutMillis;
this.allowCrossProtocolRedirects = allowCrossProtocolRedirects;
this.headers = headers;
}

@Override
protected DefaultHttpDataSource createDataSourceInternal(
RequestProperties defaultRequestProperties) {
if (this.headers != null) {
if (defaultRequestProperties == null) {
defaultRequestProperties = new RequestProperties();
}
for (Map.Entry<String, String> header : this.headers.entrySet()) {
defaultRequestProperties.set(header.getKey(), header.getValue());
}
}
DefaultHttpDataSource dataSource =
new DefaultHttpDataSource(
userAgent,
/* contentTypePredicate= */ null,
connectTimeoutMillis,
readTimeoutMillis,
allowCrossProtocolRedirects,
defaultRequestProperties);
if (listener != null) {
dataSource.addTransferListener(listener);
}
return dataSource;
}
}

private static class VideoPlayer {

private SimpleExoPlayer exoPlayer;
Expand All @@ -70,6 +123,7 @@ private static class VideoPlayer {
EventChannel eventChannel,
TextureRegistry.SurfaceTextureEntry textureEntry,
String dataSource,
Map<String, String> headers,
Result result) {
this.eventChannel = eventChannel;
this.textureEntry = textureEntry;
Expand All @@ -84,12 +138,13 @@ private static class VideoPlayer {
dataSourceFactory = new DefaultDataSourceFactory(context, "ExoPlayer");
} else {
dataSourceFactory =
new DefaultHttpDataSourceFactory(
new VideoPlayerHttpDataSourceFactory(
"ExoPlayer",
null,
DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS,
true);
true,
headers);
}

MediaSource mediaSource = buildMediaSource(uri, dataSourceFactory, context);
Expand Down Expand Up @@ -315,6 +370,7 @@ public void onMethodCall(MethodCall call, Result result) {
eventChannel,
handle,
"asset:///" + assetLookupKey,
null,
result);
videoPlayers.put(handle.id(), player);
} else {
Expand All @@ -324,6 +380,7 @@ public void onMethodCall(MethodCall call, Result result) {
eventChannel,
handle,
(String) call.argument("uri"),
(Map<String, String>) call.argument("headers"),
result);
videoPlayers.put(handle.id(), player);
}
Expand Down
21 changes: 17 additions & 4 deletions packages/video_player/ios/Classes/VideoPlayerPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ @interface FLTVideoPlayer : NSObject <FlutterTexture, FlutterStreamHandler>
@property(nonatomic, readonly) bool isPlaying;
@property(nonatomic, readonly) bool isLooping;
@property(nonatomic, readonly) bool isInitialized;
- (instancetype)initWithURL:(NSURL*)url frameUpdater:(FLTFrameUpdater*)frameUpdater;
- (instancetype)initWithURL:(NSURL*)url
headers:(NSDictionary*)headers
frameUpdater:(FLTFrameUpdater*)frameUpdater;
- (void)play;
- (void)pause;
- (void)setIsLooping:(bool)isLooping;
Expand All @@ -52,17 +54,26 @@ - (void)updatePlayingState;
@implementation FLTVideoPlayer
- (instancetype)initWithAsset:(NSString*)asset frameUpdater:(FLTFrameUpdater*)frameUpdater {
NSString* path = [[NSBundle mainBundle] pathForResource:asset ofType:nil];
return [self initWithURL:[NSURL fileURLWithPath:path] frameUpdater:frameUpdater];
return [self initWithURL:[NSURL fileURLWithPath:path] headers:nil frameUpdater:frameUpdater];
}

- (instancetype)initWithURL:(NSURL*)url frameUpdater:(FLTFrameUpdater*)frameUpdater {
- (instancetype)initWithURL:(NSURL*)url
headers:(NSDictionary*)headers
frameUpdater:(FLTFrameUpdater*)frameUpdater {
self = [super init];
NSAssert(self, @"super init cannot be nil");
_isInitialized = false;
_isPlaying = false;
_disposed = false;

AVPlayerItem* item = [AVPlayerItem playerItemWithURL:url];
AVPlayerItem* item;
if (headers) {
AVURLAsset* asset = [AVURLAsset URLAssetWithURL:url
options:@{@"AVURLAssetHTTPHeaderFieldsKey" : headers}];
item = [AVPlayerItem playerItemWithAsset:asset];
} else {
item = [AVPlayerItem playerItemWithURL:url];
}
[item addObserver:self
forKeyPath:@"loadedTimeRanges"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
Expand Down Expand Up @@ -340,7 +351,9 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
player = [[FLTVideoPlayer alloc] initWithAsset:assetPath frameUpdater:frameUpdater];
} else {
dataSource = argsMap[@"uri"];
NSDictionary* headers = argsMap[@"headers"];
player = [[FLTVideoPlayer alloc] initWithURL:[NSURL URLWithString:dataSource]
headers:headers
frameUpdater:frameUpdater];
}
int64_t textureId = [_registry registerTexture:player];
Expand Down
10 changes: 8 additions & 2 deletions packages/video_player/lib/video_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,15 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
/// package and null otherwise.
VideoPlayerController.asset(this.dataSource, {this.package})
: dataSourceType = DataSourceType.asset,
headers = null,
super(VideoPlayerValue(duration: null));

/// Constructs a [VideoPlayerController] playing a video from obtained from
/// the network.
///
/// The URI for the video is given by the [dataSource] argument and must not be
/// null.
VideoPlayerController.network(this.dataSource)
VideoPlayerController.network(this.dataSource, {this.headers})
: dataSourceType = DataSourceType.network,
package = null,
super(VideoPlayerValue(duration: null));
Expand All @@ -168,10 +169,12 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
: dataSource = 'file://${file.path}',
dataSourceType = DataSourceType.file,
package = null,
headers = null,
super(VideoPlayerValue(duration: null));

int _textureId;
final String dataSource;
final Map<String, String> headers;

/// Describes the type of data source this [VideoPlayerController]
/// is constructed with.
Expand Down Expand Up @@ -200,7 +203,10 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
};
break;
case DataSourceType.network:
dataSourceDescription = <String, dynamic>{'uri': dataSource};
dataSourceDescription = <String, dynamic>{
'uri': dataSource,
'headers': headers
};
break;
case DataSourceType.file:
dataSourceDescription = <String, dynamic>{'uri': dataSource};
Expand Down
2 changes: 2 additions & 0 deletions packages/video_player/test/video_player_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class FakeController extends ValueNotifier<VideoPlayerValue>
@override
String get dataSource => '';
@override
Map<String, String> get headers => null;
@override
DataSourceType get dataSourceType => DataSourceType.file;
@override
String get package => null;
Expand Down