Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
f31ecb0
Upgraded to exoPlayer 2.17.0
abdelaziz-mahdy Mar 6, 2022
e708902
fixed (onPlayerError override not working)
abdelaziz-mahdy Mar 6, 2022
a5f8e6f
formatted code
abdelaziz-mahdy Mar 8, 2022
c859b17
changed changelog and pubspec
abdelaziz-mahdy Mar 8, 2022
1b7a127
Fix CHANGELOG
stuartmorgan-g Mar 10, 2022
aa296a4
Merge branch 'main' into main
stuartmorgan-g Mar 23, 2022
012c42f
Update version
stuartmorgan-g Mar 23, 2022
a23cc11
added http headers to file constuctor
abdelaziz-mahdy Aug 6, 2022
d38bddc
removed if condition
abdelaziz-mahdy Aug 6, 2022
afee9ba
Merge branch 'main' of https://github.com/flutter/plugins into passin…
abdelaziz-mahdy Aug 6, 2022
00d26c0
versions updates,formating
abdelaziz-mahdy Aug 6, 2022
cbfb811
fixed missing value in constructor
abdelaziz-mahdy Aug 6, 2022
51659d1
added print to test value
abdelaziz-mahdy Aug 6, 2022
2dba163
testing prints
abdelaziz-mahdy Aug 6, 2022
99f86bb
new print
abdelaziz-mahdy Aug 6, 2022
bd4c6ce
importing log
abdelaziz-mahdy Aug 6, 2022
22c0d39
to string added
abdelaziz-mahdy Aug 6, 2022
a8ff4f5
testing new logic
abdelaziz-mahdy Aug 6, 2022
f8499c2
removed unused code
abdelaziz-mahdy Aug 6, 2022
daf919f
trying new logic
abdelaziz-mahdy Aug 6, 2022
95bb752
removed new keyword
abdelaziz-mahdy Aug 6, 2022
f5288da
new logic applied
abdelaziz-mahdy Aug 6, 2022
cae6544
uri added again
abdelaziz-mahdy Aug 6, 2022
c333d43
added option to allow diffrent user agent
abdelaziz-mahdy Aug 6, 2022
5eb2a37
wrong declration fixed
abdelaziz-mahdy Aug 6, 2022
d164e2d
string for user agent
abdelaziz-mahdy Aug 6, 2022
03e8e6b
fixed map error
abdelaziz-mahdy Aug 6, 2022
fa5c660
formating and changelog changes
abdelaziz-mahdy Aug 6, 2022
385c879
goes to normal httpDataSourceFactory incase no http header is defined
abdelaziz-mahdy Aug 6, 2022
24f3c20
Merge https://github.com/zezo357/plugins into passing-httpHeaders-to-…
abdelaziz-mahdy Sep 3, 2022
6c3caf0
added tests
abdelaziz-mahdy Sep 3, 2022
892c51c
formatting
abdelaziz-mahdy Sep 3, 2022
801f15b
Update packages/video_player/video_player/CHANGELOG.md
abdelaziz-mahdy Oct 19, 2022
f247b0d
Update packages/video_player/video_player/lib/video_player.dart
abdelaziz-mahdy Oct 19, 2022
9946c86
Update packages/video_player/video_player_android/CHANGELOG.md
abdelaziz-mahdy Oct 19, 2022
019a6b7
formatting/ and comments
abdelaziz-mahdy Oct 19, 2022
11c4b4e
fixed error
abdelaziz-mahdy Oct 20, 2022
021d0e9
Merge remote-tracking branch 'upstream/main' into passing-httpHeaders…
camsim99 Dec 20, 2022
49eed6a
Formatting
camsim99 Dec 20, 2022
46120a9
Fix merge
camsim99 Dec 20, 2022
e15b3a5
Undo formatting changes
camsim99 Dec 20, 2022
c1732d5
Undo webview change
camsim99 Dec 20, 2022
f6aea05
Merge remote-tracking branch 'upstream/main' into passing-httpHeaders…
camsim99 Jan 25, 2023
1f0c702
Undo formatting changees for clarity
camsim99 Jan 25, 2023
315d460
Add tests
camsim99 Jan 25, 2023
abb9037
fixed dart test
abdelaziz-mahdy Jan 27, 2023
cb6e378
formatting
abdelaziz-mahdy Jan 27, 2023
1d15a23
updated change logs
abdelaziz-mahdy Jan 27, 2023
55923d9
updated version
abdelaziz-mahdy Jan 27, 2023
4ce6747
removed next since new version exists
abdelaziz-mahdy Feb 1, 2023
bac9c75
fixed spacing
abdelaziz-mahdy Feb 1, 2023
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
3 changes: 2 additions & 1 deletion packages/video_player/video_player/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## NEXT
## 2.5.2

* Updates minimum Flutter version to 3.0.
* Added option to configure HTTP headers via `VideoPlayerController` to fix access to M3U8 files on Android.

## 2.5.1

Expand Down
8 changes: 5 additions & 3 deletions packages/video_player/video_player/lib/video_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
/// null.
/// **Android only**: The [formatHint] option allows the caller to override
/// the video format detection code.
/// [httpHeaders] option allows to specify HTTP headers
/// [httpHeaders] option allows to specify HTTP headers and optionally, the User-Agent
/// for the request to the [dataSource].
VideoPlayerController.network(
this.dataSource, {
Expand All @@ -247,13 +247,14 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
///
/// This will load the file from a file:// URI constructed from [file]'s path.
VideoPlayerController.file(File file,
{Future<ClosedCaptionFile>? closedCaptionFile, this.videoPlayerOptions})
{Future<ClosedCaptionFile>? closedCaptionFile,
this.videoPlayerOptions,
this.httpHeaders = const <String, String>{}})
: _closedCaptionFileFuture = closedCaptionFile,
dataSource = Uri.file(file.absolute.path).toString(),
dataSourceType = DataSourceType.file,
package = null,
formatHint = null,
httpHeaders = const <String, String>{},
super(VideoPlayerValue(duration: Duration.zero));

/// Constructs a [VideoPlayerController] playing a video from a contentUri.
Expand Down Expand Up @@ -344,6 +345,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
dataSourceDescription = DataSource(
sourceType: DataSourceType.file,
uri: dataSource,
httpHeaders: httpHeaders,
);
break;
case DataSourceType.contentUri:
Expand Down
2 changes: 1 addition & 1 deletion packages/video_player/video_player/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for displaying inline video with other Flutter
widgets on Android, iOS, and web.
repository: https://github.com/flutter/plugins/tree/main/packages/video_player/video_player
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
version: 2.5.1
version: 2.5.2

environment:
sdk: ">=2.14.0 <3.0.0"
Expand Down
16 changes: 16 additions & 0 deletions packages/video_player/video_player/test/video_player_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,22 @@ void main() {
reason: 'Actual string: $uri');
}, skip: kIsWeb /* Web does not support file assets. */);

test('file with headers (m3u8)', () async {
final VideoPlayerController controller = VideoPlayerController.file(
File('a.avi'),
httpHeaders: <String, String>{'Authorization': 'Bearer token'},
);
await controller.initialize();

final String uri = fakeVideoPlayerPlatform.dataSources[0].uri!;
expect(uri.startsWith('file:///'), true, reason: 'Actual string: $uri');
expect(uri.endsWith('/a.avi'), true, reason: 'Actual string: $uri');

expect(
fakeVideoPlayerPlatform.dataSources[0].httpHeaders,
<String, String>{'Authorization': 'Bearer token'},
);
}, skip: kIsWeb /* Web does not support file assets. */);
test('successful initialize on controller with error clears error',
() async {
final VideoPlayerController controller = VideoPlayerController.network(
Expand Down
4 changes: 4 additions & 0 deletions packages/video_player/video_player_android/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
* Fixes violations of new analysis option use_named_constants.
* Removes an unnecessary override in example code.

## 2.3.10

* Added option to configure the User-Agent in the HTTP headers for the ExoPlayer agent.

## 2.3.9

* Updates ExoPlayer to 2.18.1.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,14 @@ final class VideoPlayer {

private final EventChannel eventChannel;

private final String USER_AGENT = "User-Agent";

@VisibleForTesting boolean isInitialized = false;

private final VideoPlayerOptions options;

private DefaultHttpDataSource.Factory httpDataSourceFactory = new DefaultHttpDataSource.Factory();

VideoPlayer(
Context context,
EventChannel eventChannel,
Expand All @@ -73,23 +77,11 @@ final class VideoPlayer {
this.options = options;

ExoPlayer exoPlayer = new ExoPlayer.Builder(context).build();

Uri uri = Uri.parse(dataSource);
DataSource.Factory dataSourceFactory;

if (isHTTP(uri)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zezo357 I am ready to add tests but I have some follow up questions first to make sure I understand the change.

  1. Why did you delete the check for isHttp(...) and use new DefaultDataSource.Factory(context, httpDataSourceFactory) by default versus httpDataSourceFactory.setDefaultRequestProperties(httpHeaders)? What happens if the uri is not HTTP?
  2. As a follow up to (1), was the fix for passing mu38 files to add the .setUserAgent(httpHeaders.get(USER_AGENT)) line if USER_AGENT is present the HTTP headers?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1-If not http all functions will work and it's the main fix since when playing a m3u8 file it's not http

2- user agent should be added to the http headers If the user wants it (it's needed because some hosts do not allow the default user agent)

DefaultHttpDataSource.Factory httpDataSourceFactory =
new DefaultHttpDataSource.Factory()
.setUserAgent("ExoPlayer")
.setAllowCrossProtocolRedirects(true);

if (httpHeaders != null && !httpHeaders.isEmpty()) {
httpDataSourceFactory.setDefaultRequestProperties(httpHeaders);
}
dataSourceFactory = httpDataSourceFactory;
} else {
dataSourceFactory = new DefaultDataSource.Factory(context);
}
buildHttpDataSourceFactory(httpHeaders);
DataSource.Factory dataSourceFactory =
new DefaultDataSource.Factory(context, httpDataSourceFactory);

MediaSource mediaSource = buildMediaSource(uri, dataSourceFactory, formatHint, context);

Expand All @@ -106,20 +98,29 @@ final class VideoPlayer {
EventChannel eventChannel,
TextureRegistry.SurfaceTextureEntry textureEntry,
VideoPlayerOptions options,
QueuingEventSink eventSink) {
QueuingEventSink eventSink,
DefaultHttpDataSource.Factory httpDataSourceFactory) {
this.eventChannel = eventChannel;
this.textureEntry = textureEntry;
this.options = options;
this.httpDataSourceFactory = httpDataSourceFactory;

setUpVideoPlayer(exoPlayer, eventSink);
}

private static boolean isHTTP(Uri uri) {
if (uri == null || uri.getScheme() == null) {
return false;
@VisibleForTesting
public void buildHttpDataSourceFactory(@NonNull Map<String, String> httpHeaders) {
final boolean httpHeadersNotEmpty = httpHeaders != null && !httpHeaders.isEmpty();
final String userAgent =
httpHeadersNotEmpty && httpHeaders.containsKey(USER_AGENT)
? httpHeaders.get(USER_AGENT)
: "ExoPlayer";

httpDataSourceFactory.setUserAgent(userAgent).setAllowCrossProtocolRedirects(true);

if (httpHeadersNotEmpty) {
httpDataSourceFactory.setDefaultRequestProperties(httpHeaders);
}
String scheme = uri.getScheme();
return scheme.equals("http") || scheme.equals("https");
}

private MediaSource buildMediaSource(
Expand Down Expand Up @@ -149,13 +150,11 @@ private MediaSource buildMediaSource(
switch (type) {
case C.CONTENT_TYPE_SS:
return new SsMediaSource.Factory(
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
new DefaultDataSource.Factory(context, mediaDataSourceFactory))
new DefaultSsChunkSource.Factory(mediaDataSourceFactory), mediaDataSourceFactory)
.createMediaSource(MediaItem.fromUri(uri));
case C.CONTENT_TYPE_DASH:
return new DashMediaSource.Factory(
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
new DefaultDataSource.Factory(context, mediaDataSourceFactory))
new DefaultDashChunkSource.Factory(mediaDataSourceFactory), mediaDataSourceFactory)
.createMediaSource(MediaItem.fromUri(uri));
case C.CONTENT_TYPE_HLS:
return new HlsMediaSource.Factory(mediaDataSourceFactory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@
package io.flutter.plugins.videoplayer;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import io.flutter.plugin.common.EventChannel;
import io.flutter.view.TextureRegistry;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand All @@ -29,6 +34,7 @@ public class VideoPlayerTest {
private TextureRegistry.SurfaceTextureEntry fakeSurfaceTextureEntry;
private VideoPlayerOptions fakeVideoPlayerOptions;
private QueuingEventSink fakeEventSink;
private DefaultHttpDataSource.Factory httpDataSourceFactorySpy;

@Captor private ArgumentCaptor<HashMap<String, Object>> eventCaptor;

Expand All @@ -41,6 +47,76 @@ public void before() {
fakeSurfaceTextureEntry = mock(TextureRegistry.SurfaceTextureEntry.class);
fakeVideoPlayerOptions = mock(VideoPlayerOptions.class);
fakeEventSink = mock(QueuingEventSink.class);
httpDataSourceFactorySpy = spy(new DefaultHttpDataSource.Factory());
}

@Test
public void videoPlayer_BuildsHttpDataSourceFactoryProperlyWhenHttpHeadersNull() {
VideoPlayer videoPlayer =
new VideoPlayer(
fakeExoPlayer,
fakeEventChannel,
fakeSurfaceTextureEntry,
fakeVideoPlayerOptions,
fakeEventSink,
httpDataSourceFactorySpy);

videoPlayer.buildHttpDataSourceFactory(new HashMap<>());

verify(httpDataSourceFactorySpy).setUserAgent("ExoPlayer");
verify(httpDataSourceFactorySpy).setAllowCrossProtocolRedirects(true);
verify(httpDataSourceFactorySpy, never()).setDefaultRequestProperties(any());
}

@Test
public void
videoPlayer_BuildsHttpDataSourceFactoryProperlyWhenHttpHeadersNonNullAndUserAgentSpecified() {
VideoPlayer videoPlayer =
new VideoPlayer(
fakeExoPlayer,
fakeEventChannel,
fakeSurfaceTextureEntry,
fakeVideoPlayerOptions,
fakeEventSink,
httpDataSourceFactorySpy);
Map<String, String> httpHeaders =
new HashMap<String, String>() {
{
put("header", "value");
put("User-Agent", "userAgent");
}
};

videoPlayer.buildHttpDataSourceFactory(httpHeaders);

verify(httpDataSourceFactorySpy).setUserAgent("userAgent");
verify(httpDataSourceFactorySpy).setAllowCrossProtocolRedirects(true);
verify(httpDataSourceFactorySpy).setDefaultRequestProperties(httpHeaders);
}

@Test
public void
videoPlayer_BuildsHttpDataSourceFactoryProperlyWhenHttpHeadersNonNullAndUserAgentNotSpecified() {
VideoPlayer videoPlayer =
new VideoPlayer(
fakeExoPlayer,
fakeEventChannel,
fakeSurfaceTextureEntry,
fakeVideoPlayerOptions,
fakeEventSink,
httpDataSourceFactorySpy);
Map<String, String> httpHeaders =
new HashMap<String, String>() {
{
put("header", "value");
}
};

videoPlayer.buildHttpDataSourceFactory(httpHeaders);

verify(httpDataSourceFactorySpy).setUserAgent("ExoPlayer");
verify(httpDataSourceFactorySpy).setAllowCrossProtocolRedirects(true);
verify(httpDataSourceFactorySpy).setDefaultRequestProperties(httpHeaders);
}

@Test
Expand All @@ -51,7 +127,8 @@ public void sendInitializedSendsExpectedEvent_90RotationDegrees() {
fakeEventChannel,
fakeSurfaceTextureEntry,
fakeVideoPlayerOptions,
fakeEventSink);
fakeEventSink,
httpDataSourceFactorySpy);
Format testFormat =
new Format.Builder().setWidth(100).setHeight(200).setRotationDegrees(90).build();

Expand Down Expand Up @@ -79,7 +156,8 @@ public void sendInitializedSendsExpectedEvent_270RotationDegrees() {
fakeEventChannel,
fakeSurfaceTextureEntry,
fakeVideoPlayerOptions,
fakeEventSink);
fakeEventSink,
httpDataSourceFactorySpy);
Format testFormat =
new Format.Builder().setWidth(100).setHeight(200).setRotationDegrees(270).build();

Expand Down Expand Up @@ -107,7 +185,8 @@ public void sendInitializedSendsExpectedEvent_0RotationDegrees() {
fakeEventChannel,
fakeSurfaceTextureEntry,
fakeVideoPlayerOptions,
fakeEventSink);
fakeEventSink,
httpDataSourceFactorySpy);
Format testFormat =
new Format.Builder().setWidth(100).setHeight(200).setRotationDegrees(0).build();

Expand Down Expand Up @@ -135,7 +214,8 @@ public void sendInitializedSendsExpectedEvent_180RotationDegrees() {
fakeEventChannel,
fakeSurfaceTextureEntry,
fakeVideoPlayerOptions,
fakeEventSink);
fakeEventSink,
httpDataSourceFactorySpy);
Format testFormat =
new Format.Builder().setWidth(100).setHeight(200).setRotationDegrees(180).build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class AndroidVideoPlayer extends VideoPlayerPlatform {
break;
case DataSourceType.file:
uri = dataSource.uri;
httpHeaders = dataSource.httpHeaders;
break;
case DataSourceType.contentUri:
uri = dataSource.uri;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,18 @@ void main() {
expect(textureId, 3);
});

test('create with file (some headers)', () async {
final int? textureId = await player.create(DataSource(
sourceType: DataSourceType.file,
uri: 'someUri',
httpHeaders: <String, String>{'Authorization': 'Bearer token'},
));
expect(log.log.last, 'create');
expect(log.createMessage?.uri, 'someUri');
expect(log.createMessage?.httpHeaders,
<String, String>{'Authorization': 'Bearer token'});
expect(textureId, 3);
});
test('setLooping', () async {
await player.setLooping(1, true);
expect(log.log.last, 'setLooping');
Expand Down