Skip to content

Commit

Permalink
Feature/august changes (jhomlala#649)
Browse files Browse the repository at this point in the history
* Added licenseUrl support for iOS DRM.

* Fixed RTL text direction issue in player controls.

* Updated normal player page

* Added currently displayed subtitle

* Added additional check in `postControllerEvent` to handle scenario where event stream is closed.

* Updated ExoPlayer version

* Buffering fix in Android, video list update

* * Added `setMixWithOthers` method in `BetterPlayerListVideoPlayerController`.

* Fixed broken ling in cover page of documentatio

* Fixed progress bar issue where position could be set above video duration

* Fixed iOS remote notification command issu

* Update welcome_page.dart (jhomlala#607)

Removed duplicated page

* Removed duplicated page in example app (by https://github.com/pinguluk)

* Added support for ClearKey DRM for File Datasource. (jhomlala#566)

* Added support for ClearKey DRM for File Datasource.

* Formatting of ClearKey implementation code.

* Added ClearKey support for BetterPlayerDataSourceType.network and BetterPlayerDataSourceType.memory for Android.

* Added ClearKey DRM to new documentation format.

* Clear key DRM update

* Better UI Changes (jhomlala#594)

* Better UI Changes

* Update ci.yml

* Feature/july changes (jhomlala#598)

* Fixed play after seeking issue on iOS

* Fixed audio track selection issue on iOS/Android

* Fixed issue where speed which couldn't be applied on iOS was saved in player state.

* Added support for D-pad navigation using a Android TV remote control (jhomlala#586)

* Exposes all active eventListener (jhomlala#585)

* Updated changelog

* Added docs

* Updated documentation

* Updated documentation

* Added BetterPlayerMultipleGestureDetector, general refactor

* General refactor

Co-authored-by: Daniel Zarins <74965667+danielz-nenda@users.noreply.github.com>
Co-authored-by: Letalus <41230136+Letalus@users.noreply.github.com>

* Updated docs

* Updated docs

* Updated docs

* Updated docs

* fixed conflicts

* Duplicated named argument 'onLongPress' removed

* Better UI Changes

* Feature/july changes (jhomlala#598)

* Fixed play after seeking issue on iOS

* Fixed audio track selection issue on iOS/Android

* Fixed issue where speed which couldn't be applied on iOS was saved in player state.

* Added support for D-pad navigation using a Android TV remote control (jhomlala#586)

* Exposes all active eventListener (jhomlala#585)

* Updated changelog

* Added docs

* Updated documentation

* Updated documentation

* Added BetterPlayerMultipleGestureDetector, general refactor

* General refactor

Co-authored-by: Daniel Zarins <74965667+danielz-nenda@users.noreply.github.com>
Co-authored-by: Letalus <41230136+Letalus@users.noreply.github.com>

* fixed conflicts

Co-authored-by: Jakub <jhomlala@gmail.com>
Co-authored-by: Daniel Zarins <74965667+danielz-nenda@users.noreply.github.com>
Co-authored-by: Letalus <41230136+Letalus@users.noreply.github.com>

* Updated changelog

* Added `sigmaX` and `sigmaY` parameters in BetterPlayerControlsConfiguration

* Updated lint and format

* Updated versions

Co-authored-by: Pinguluk <luca_paun@yahoo.com>
Co-authored-by: tinusneethling <59045462+tinusneethling@users.noreply.github.com>
Co-authored-by: creativeblaq <76699978+creativeblaq@users.noreply.github.com>
Co-authored-by: Daniel Zarins <74965667+danielz-nenda@users.noreply.github.com>
Co-authored-by: Letalus <41230136+Letalus@users.noreply.github.com>
  • Loading branch information
6 people authored Aug 15, 2021
1 parent e1ecdbd commit 99bb898
Show file tree
Hide file tree
Showing 48 changed files with 1,152 additions and 541 deletions.
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

0 comments on commit 99bb898

Please sign in to comment.