Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/august changes #649

Merged
merged 20 commits into from
Aug 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
## 0.0.73
* Added `licenseUrl` support for iOS DRM.
* Fixed RTL text direction issue in player controls.
* Added `renderedSubtitle` in `BetterPlayerController`.
* Added additional check in `postControllerEvent` to handle scenario where event stream is closed.
* Updated ExoPlayer version
* Fixed `bufferingUpdate` event triggered too often.
* Updated video list example with bufering configuration.
* Updated video list documentation.
* Added `setMixWithOthers` method in `BetterPlayerListVideoPlayerController`.
* Fixed broken link in cover page of documentation.
* Fixed progress bar issue where position could be set above video duration.
* Fixed iOS remote notification command issue.
* Removed duplicated page in example app (by https://github.com/pinguluk)
* Added support for clear key DRM (by https://github.com/tinusneethling)
* Refreshed look and feel of the player UI (by https://github.com/creativeblaq)
* Added `sigmaX` and `sigmaY` parameters in BetterPlayerControlsConfiguration to control blur of cupertino controls (original idea by: https://github.com/YeFei572)

## 0.0.72
* Updated ExoPlayer version

Expand Down
1 change: 1 addition & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ linter:
sized_box_for_whitespace: false
invalid_dependency: false
sort_pub_dependencies: false
avoid_unnecessary_containers: false

12 changes: 6 additions & 6 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ android {
}

dependencies {
implementation 'com.google.android.exoplayer:exoplayer-core:2.14.1'
implementation 'com.google.android.exoplayer:exoplayer-hls:2.14.1'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.14.1'
implementation 'com.google.android.exoplayer:exoplayer-smoothstreaming:2.14.1'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.14.1'
implementation 'com.google.android.exoplayer:extension-mediasession:2.14.1'
implementation 'com.google.android.exoplayer:exoplayer-core:2.14.2'
implementation 'com.google.android.exoplayer:exoplayer-hls:2.14.2'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.14.2'
implementation 'com.google.android.exoplayer:exoplayer-smoothstreaming:2.14.2'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.14.2'
implementation 'com.google.android.exoplayer:extension-mediasession:2.14.2'
implementation "android.arch.lifecycle:runtime:1.1.1"
implementation "android.arch.lifecycle:common:1.1.1"
implementation "android.arch.lifecycle:common-java8:1.1.1"
Expand Down
35 changes: 26 additions & 9 deletions android/src/main/java/com/jhomlala/better_player/BetterPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import com.google.android.exoplayer2.drm.DummyExoMediaDrm;
import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
import com.google.android.exoplayer2.drm.LocalMediaDrmCallback;
import com.google.android.exoplayer2.drm.UnsupportedDrmException;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
Expand Down Expand Up @@ -111,6 +112,7 @@ final class BetterPlayer {
private WorkManager workManager;
private HashMap<UUID, Observer<WorkInfo>> workerObserverMap;
private CustomDefaultLoadControl customDefaultLoadControl;
private long lastSendBufferedPosition = 0L;


BetterPlayer(
Expand Down Expand Up @@ -147,7 +149,7 @@ void setDataSource(
Context context, String key, String dataSource, String formatHint, Result result,
Map<String, String> headers, boolean useCache, long maxCacheSize, long maxCacheFileSize,
long overriddenDuration, String licenseUrl, Map<String, String> drmHeaders,
String cacheKey) {
String cacheKey, String clearKey) {
this.key = key;
isInitialized = false;

Expand Down Expand Up @@ -189,6 +191,16 @@ void setDataSource(
.build(httpMediaDrmCallback);
}
}
} else if (clearKey != null && !clearKey.isEmpty()) {
if (Util.SDK_INT < 18) {
Log.e(TAG, "Protected content not supported on API levels below 18");
drmSessionManager = null;
} else {
drmSessionManager = new DefaultDrmSessionManager.Builder()
.setUuidAndExoMediaDrmProvider(C.CLEARKEY_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER).
build(new LocalMediaDrmCallback(clearKey.getBytes()));
}

} else {
drmSessionManager = null;
}
Expand Down Expand Up @@ -556,8 +568,9 @@ public void onCancel(Object o) {
exoPlayer.addListener(new Player.Listener() {
@Override
public void onPlaybackStateChanged(int playbackState) {

if (playbackState == Player.STATE_BUFFERING) {
sendBufferingUpdate();
sendBufferingUpdate(true);
Map<String, Object> event = new HashMap<>();
event.put("event", "bufferingStart");
eventSink.success(event);
Expand Down Expand Up @@ -590,13 +603,17 @@ public void onPlayerError(final ExoPlaybackException error) {
result.success(reply);
}

void sendBufferingUpdate() {
Map<String, Object> event = new HashMap<>();
event.put("event", "bufferingUpdate");
List<? extends Number> range = Arrays.asList(0, exoPlayer.getBufferedPosition());
// iOS supports a list of buffered ranges, so here is a list with a single range.
event.put("values", Collections.singletonList(range));
eventSink.success(event);
void sendBufferingUpdate(boolean isFromBufferingStart) {
long bufferedPosition = exoPlayer.getBufferedPosition();
if (isFromBufferingStart || bufferedPosition != lastSendBufferedPosition) {
Map<String, Object> event = new HashMap<>();
event.put("event", "bufferingUpdate");
List<? extends Number> range = Arrays.asList(0, bufferedPosition);
// iOS supports a list of buffered ranges, so here is a list with a single range.
event.put("values", Collections.singletonList(range));
eventSink.success(event);
lastSendBufferedPosition = bufferedPosition;
}
}

private void setAudioAttributes(SimpleExoPlayer exoPlayer, Boolean mixWithOthers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public class BetterPlayerPlugin implements FlutterPlugin, ActivityAware, MethodC
private static final String INDEX_PARAMETER = "index";
private static final String LICENSE_URL_PARAMETER = "licenseUrl";
private static final String DRM_HEADERS_PARAMETER = "drmHeaders";
private static final String DRM_CLEARKEY_PARAMETER = "clearKey";
private static final String MIX_WITH_OTHERS_PARAMETER = "mixWithOthers";
public static final String URL_PARAMETER = "url";
public static final String PRE_CACHE_SIZE_PARAMETER = "preCacheSize";
Expand Down Expand Up @@ -238,7 +239,7 @@ private void onMethodCall(MethodCall call, Result result, long textureId, Better
break;
case POSITION_METHOD:
result.success(player.getPosition());
player.sendBufferingUpdate();
player.sendBufferingUpdate(false);
break;
case ABSOLUTE_POSITION_METHOD:
result.success(player.getAbsolutePosition());
Expand Down Expand Up @@ -305,7 +306,7 @@ private void setDataSource(MethodCall call, Result result, BetterPlayer player)
assetLookupKey = flutterState.keyForAsset.get(asset);
}

player.setDataSource(
player.setDataSource(
flutterState.applicationContext,
key,
"asset:///" + assetLookupKey,
Expand All @@ -317,7 +318,7 @@ private void setDataSource(MethodCall call, Result result, BetterPlayer player)
0L,
overriddenDuration.longValue(),
null,
null, null
null, null, null
);
} else {
boolean useCache = getParameter(dataSource, USE_CACHE_PARAMETER, false);
Expand All @@ -329,6 +330,7 @@ private void setDataSource(MethodCall call, Result result, BetterPlayer player)
String cacheKey = getParameter(dataSource, CACHE_KEY_PARAMETER, null);
String formatHint = getParameter(dataSource, FORMAT_HINT_PARAMETER, null);
String licenseUrl = getParameter(dataSource, LICENSE_URL_PARAMETER, null);
String clearKey = getParameter(dataSource, DRM_CLEARKEY_PARAMETER, null);
Map<String, String> drmHeaders = getParameter(dataSource, DRM_HEADERS_PARAMETER, new HashMap<>());
player.setDataSource(
flutterState.applicationContext,
Expand All @@ -343,7 +345,8 @@ private void setDataSource(MethodCall call, Result result, BetterPlayer player)
overriddenDuration.longValue(),
licenseUrl,
drmHeaders,
cacheKey
cacheKey,
clearKey
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion docs/_coverpage.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
- Supports both Android and iOS

[GitHub](https://github.com/jhomlala/betterplayer)
[Get Started](#gettingstarted)
[Get Started](#home)
6 changes: 6 additions & 0 deletions docs/controlsconfiguration.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,10 @@ final Widget loadingWidget;

///Color of the background, when no frame is displayed.
final Color backgroundColor;

///Quality of Gaussian Blur for x (iOS only).
final double sigmaX;

///Quality of Gaussian Blur for y (iOS only).
final double sigmaY;
```
46 changes: 44 additions & 2 deletions docs/drmconfiguration.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Supported DRMs:

* Token based (authorization header): Android/iOS
* Widevine (licensue url + headers): Android
* Fairplay EZDRM (certificate url): iOS
* Fairplay EZDRM (certificate url, license url): iOS

Additional DRM types may be added in the future.

Expand Down Expand Up @@ -42,6 +42,48 @@ BetterPlayerDataSource _fairplayDataSource = BetterPlayerDataSource(
drmConfiguration: BetterPlayerDrmConfiguration(
drmType: BetterPlayerDrmType.fairplay,
certificateUrl: Constants.fairplayCertificateUrl,
licenseUrl: Constants.fairplayLicenseUrl,
),
);
```
```

ClearKey (only supported in Android):

A ClearKey MP4 file can be generated with MP4Box as follow:

- Create drm_file.xml with the following contents.
```xml
<GPACDRM type="CENC AES-CTR">
<DRMInfo type="pssh" version="1">
<BS ID128="1077efecc0b24d02ace33c1e52e2fb4b"/>
<BS bits="32" value="1"/>
<BS ID128="cd7eb9ff88f34caeb06185b00024e4c2"/>
</DRMInfo>
<CrypTrack IV_size="8" first_IV="0xbb5738fe08f11341" isEncrypted="1" saiSavedBox="senc" trackID="1">
<key KID="f3c5e0361e6654b28f8049c778b23946" value="a4631a153a443df9eed0593043db7519"/>
</CrypTrack>
<CrypTrack IV_size="8" first_IV="0xbb5738fe08f11341" isEncrypted="1" saiSavedBox="senc" trackID="2">
<key KID="f3c5e0361e6654b28f8049c778b23946" value="a4631a153a443df9eed0593043db7519"/>
</CrypTrack>

</GPACDRM>


```
- Create the mp4 container using [MP4Box](https://gpac.wp.imt.fr/)
- MP4Box -crypt drm_file.xml testvideo.mp4 -out testvideo_encrypt_tmp.mp4
- MP4Box -frag 240000 testvideo_encrypt_tmp.mp4 -out testvideo_encrypt.mp4 (need to create multi segment mp4 file as ExoPlayer does not read the pssh block on a single segment mp4 file)
```dart

var _clearKeyDataSourceFile = BetterPlayerDataSource(
BetterPlayerDataSourceType.file,
await Utils.getFileUrl(Constants.fileTestVideoEncryptUrl),
drmConfiguration: BetterPlayerDrmConfiguration(
drmType: BetterPlayerDrmType.clearKey,
clearKey: BetterPlayerClearKeyUtils.generate({
"f3c5e0361e6654b28f8049c778b23946":
"a4631a153a443df9eed0593043db7519",
"abba271e8bcf552bbd2e86a434a9a5d9":
"69eaa802a6763af979e8d1940fb88392"
})),
);
2 changes: 1 addition & 1 deletion docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```yaml
dependencies:
better_player: ^0.0.72
better_player: ^0.0.73
```

2. Install it
Expand Down
4 changes: 3 additions & 1 deletion docs/listplayerusage.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@

You can control `BetterPlayerListViewPlayer` with `BetterPlayerListViewPlayerController`. You need to pass `BetterPlayerListViewPlayerController` to `BetterPlayerListVideoPlayer`. See more in example app.

`BetterPlayerListViewPlayer` is good solution if you know that your list will be not too long. If you know that your list of videos will be long then you need to recycle `BetterPlayerController` instances. This is required because each creation of `BetterPlayerController` requires a lot of resources of the device. You need to remember that there are some devices which allows to create 2-3 instances of `BetterPlayerController` due to low hardware specification. To handle problem like this, you should use **recycle/reusable** techniques, where you will create 2-3 instances of `BetterPlayerController` and simply reuse them in list cell. See reusable video list example here: https://github.com/jhomlala/betterplayer/tree/master/example/lib/pages/reusable_video_list
`BetterPlayerListViewPlayer` is good solution if you know that your list will be not too long. If you know that your list of videos will be long then you need to recycle `BetterPlayerController` instances. This is required because each creation of `BetterPlayerController` requires a lot of resources of the device. You need to remember that there are some devices which allows to create 2-3 instances of `BetterPlayerController` due to low hardware specification. To handle problem like this, you should use **recycle/reusable** techniques, where you will create 2-3 instances of `BetterPlayerController` and simply reuse them in list cell. See reusable video list example here: https://github.com/jhomlala/betterplayer/tree/master/example/lib/pages/reusable_video_list

To resolve random OOM issues, try to lower values in `bufferingConfiguration` in `BetterPlayerDataSource`.
Binary file added docs/media/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions docs/media/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@

body .app-nav {
color: #34495e !important;
}
.cover {
color: #34495e !important;
}

.cover #better-player .anchor span {
color: #34495e !important;
}

section.cover {
min-height: 100vh;
height: auto !important;
padding: 2em 0.5em;
}

section.cover .cover-main {
z-index: 0;
}

section.cover .cover-main > .buttons a {
border-radius: 2rem;
border: 1px solid var(--theme-color, #42b983);
box-sizing: border-box;
color: var(--theme-color, #42b983);
display: inline-block;
font-size: 1.05rem;
letter-spacing: 0.1rem;
margin: 0.5rem 1rem;
padding: 0.75em 2rem;
text-decoration: none;
transition: all 0.15s ease;
}
section.cover .cover-main > .buttons a:last-child {
background-color: var(--theme-color, #42b983);
color: #fff;
}
section.cover .cover-main > .buttons a:last-child:hover {
color: inherit;
opacity: 0.8;
}
section.cover .cover-main > .buttons a:hover {
color: inherit;
}
section.cover blockquote > .buttons > a {
border-bottom: 2px solid var(--theme-color, #42b983);
transition: color 0.3s;
}
section.cover blockquote > .buttons > a:hover {
color: var(--theme-color, #42b983);
}
6 changes: 5 additions & 1 deletion docs/subtitlesconfiguration.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,8 @@ final Color backgroundColor;

///Subtitles selected by default, without user interaction
final bool selectedByDefault;
```
```

## Current subtitle

To get currently displayed subtitle, use `renderedSubtitle` in `BetterPlayerController`.
Loading