Skip to content

Commit

Permalink
Feature/june changes 2 (jhomlala#563)
Browse files Browse the repository at this point in the history
* Fixed cache clear on Android

* Added file check for file data source.

* Fix for black screen issue on iOS

* Updated changelog

* fix: iOS crashes encountered mainly when playing lots of video in HLS format. I definitely encounter a crash line 380 (jhomlala#513)

* Updated changelog

* Added key parameter in BetterPlayerCacheConfiguration to provide way to re-use same video between app session

* Format, updated pubspec.yaml

* Fixed playback speed after seek in iOS.

* Exposed ASMS classes

* * Added error handling for CacheWorker to prevent unexpected crashes.

* Exposed BetterPlayerControlsState to provide ways to build custom controls with additional menus

* Fairplay ezdrm (jhomlala#488)

* Split iOS plugin into different files for each class.

* Change FlutterTexture for FlutterPlatformView to be able to display DRM encoded content on iOS.

* Change FlutterTexture for FlutterPlatformView to be able to display DRM encoded content on iOS.

* Added support for fairplay with EZDRM for iOS, "certificateUrl" added to DataSource.

* Do not reuse FLTBetterPlayerView to avoid problems on widget rebuild. Removed random key fix in wiget.

* Added fairplay certificate file from EZDRM demo project

* Added EZDRM fairplay demo video to the example drm_page

* Changed "FLTTimeUtils" to "BetterPlayerTimeUtils"

* Changed "FLTEzdrmAssetsLoaderDelegate" to "BetterPlayerAssetsLoaderDelegate"

* Removed unused function -> removeKeyWith(NSFileManager *)fileManager

* Fixed header comments

* Code formatting

Co-authored-by: Koldo <kolod@byvapps.com>
Co-authored-by: Jakub <jhomlala@gmail.com>

* Fairplay refactor

* Fairplay refactor

* Fairplay refactor

* Updated changelog

* Android load buffer implementation (jhomlala#537)

* start of load buffer implementation

* implementing a load buffer functionality for android:
Reason: When trying to load 3 videos at once, the loading duration of the video is greatly affected by the buffer rate --> therefore optimizing the buffer can hugely reduce the video loading time

* adding export better player android configuration

* converting linkedhashmap to Map<String, dynamic>

* adjusting the type

* fixing buffer channel argument name

* Added buffering configuration for Android

* Updated changelog

* Fixed file data source exception. Right now user will be only warned

* Fixed file data source exception. Right now user will be only warned

* Fixed issue where controls were not updated after video finish.

* Fixed issue where controls were not updated after video finish.

* Fixed auto full screen orientation not enabled in iOS.

* Format and lint fixes

* Format and lint fixes

Co-authored-by: themadmrj <themadmrj@users.noreply.github.com>
Co-authored-by: Alexandre Roux <alex@tekartik.com>
Co-authored-by: Koldo <koldoru92@gmail.com>
Co-authored-by: Koldo <kolod@byvapps.com>
Co-authored-by: jakubhomlala <j.homlala@bsgroup.eu>
Co-authored-by: Letalus <41230136+Letalus@users.noreply.github.com>
  • Loading branch information
7 people authored Jun 20, 2021
1 parent 5be8878 commit 569f61a
Show file tree
Hide file tree
Showing 35 changed files with 1,130 additions and 711 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
## 0.0.70
* Fixed file data source exception. Right now user will be only warned.
* Fixed playback speed after seek in iOS.
* Fixed `overriddenDuration` behavior in iOS when passed `overriddenDuration` is longer than video duration.
* Fixed issue where controls were not updated after video finish.
* Fixed auto full screen orientation not enabled in iOS.
* Exposed ASMS classes.
* Exposed BetterPlayerControlsState to provide ways to build custom controls with additional menus.
* Added error handling for CacheWorker to prevent unexpected crashes.
* Added support for FairPlay EZDRM (by https://github.com/adrianByv and https://github.com/koldo92)
* Added `certificateUrl` parameter in BetterPlayerDrmConfiguration.
* Added support for custom buffering configuration in Android (by https://github.com/Letalus)
* Added `bufferingConfiguration` parameter in BetterPlayerConfiguration which contains buffering settings.


## 0.0.69
* Fixed cache clear on Android.
* Added file check for file data source.
Expand Down
28 changes: 26 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ This plugin is based on [Chewie](https://github.com/brianegan/chewie). Chewie is
✔️ Cache support
✔️ Notifications support
✔️ Picture in Picture support
✔️ DRM support (token, Widevine)
✔️ DRM support (token, Widevine, FairPlay EZDRM)
✔️ ... and much more!


Expand All @@ -95,7 +95,7 @@ This plugin is based on [Chewie](https://github.com/brianegan/chewie). Chewie is

```yaml
dependencies:
better_player: ^0.0.69
better_player: ^0.0.70
```
2. Install it
Expand Down Expand Up @@ -764,6 +764,30 @@ Possible configuration options:
final String content;
```

### BetterPlayerBufferingConfiguration
Configuration class used to setup better buffering experience or setup custom load settings. Currently used only in Android.

Possible configuration options:
```dart
///The default minimum duration of media that the player will attempt to
///ensure is buffered at all times, in milliseconds.
final int minBufferMs;
///The default maximum duration of media that the player will attempt to
///buffer, in milliseconds.
final int maxBufferMs;
///The default duration of media that must be buffered for playback to start
///or resume following a user action such as a seek, in milliseconds.
final int bufferForPlaybackMs;
///The default duration of media that must be buffered for playback to resume
///after a rebuffer, in milliseconds. A rebuffer is defined to be caused by
///buffer depletion rather than a user action.
final int bufferForPlaybackAfterRebufferMs;
```


### BetterPlayerTranslations
You can provide translations for different languages. You need to pass list of BetterPlayerTranslations to
the BetterPlayerConfiguration. Here is an example:
Expand Down
64 changes: 41 additions & 23 deletions android/src/main/java/com/jhomlala/better_player/BetterPlayer.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
package com.jhomlala.better_player;

import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF;
import static com.jhomlala.better_player.DataSourceUtils.getDataSourceFactory;
import static com.jhomlala.better_player.DataSourceUtils.getUserAgent;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
Expand All @@ -22,21 +17,33 @@
import android.util.Log;
import android.view.Surface;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import androidx.media.session.MediaButtonReceiver;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;

import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ControlDispatcher;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.LoadControl;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.EventListener;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
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.UnsupportedDrmException;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
Expand All @@ -52,25 +59,11 @@
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.ui.PlayerNotificationManager;
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.util.Util;
import com.google.android.exoplayer2.ui.PlayerNotificationManager;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import androidx.lifecycle.Observer;
import androidx.media.session.MediaButtonReceiver;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;

import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.view.TextureRegistry;

import java.io.File;
import java.util.Arrays;
Expand All @@ -80,7 +73,14 @@
import java.util.Map;
import java.util.UUID;

import com.google.android.exoplayer2.PlaybackParameters;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.view.TextureRegistry;

import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF;
import static com.jhomlala.better_player.DataSourceUtils.getDataSourceFactory;
import static com.jhomlala.better_player.DataSourceUtils.getUserAgent;

final class BetterPlayer {
private static final String TAG = "BetterPlayer";
Expand All @@ -96,6 +96,7 @@ final class BetterPlayer {
private final QueuingEventSink eventSink = new QueuingEventSink();
private final EventChannel eventChannel;
private final DefaultTrackSelector trackSelector;
private final LoadControl loadControl;

private boolean isInitialized = false;
private Surface surface;
Expand All @@ -109,17 +110,33 @@ final class BetterPlayer {
private DrmSessionManager drmSessionManager;
private WorkManager workManager;
private HashMap<UUID, Observer<WorkInfo>> workerObserverMap;
private CustomDefaultLoadControl customDefaultLoadControl;


BetterPlayer(
Context context,
EventChannel eventChannel,
TextureRegistry.SurfaceTextureEntry textureEntry,
CustomDefaultLoadControl customDefaultLoadControl,
Result result) {
this.eventChannel = eventChannel;
this.textureEntry = textureEntry;
trackSelector = new DefaultTrackSelector(context);
exoPlayer = new SimpleExoPlayer.Builder(context).setTrackSelector(trackSelector).build();

this.customDefaultLoadControl = customDefaultLoadControl != null ?
customDefaultLoadControl : new CustomDefaultLoadControl();
DefaultLoadControl.Builder loadBuilder = new DefaultLoadControl.Builder();
loadBuilder.setBufferDurationsMs(
this.customDefaultLoadControl.minBufferMs,
this.customDefaultLoadControl.maxBufferMs,
this.customDefaultLoadControl.bufferForPlaybackMs,
this.customDefaultLoadControl.bufferForPlaybackAfterRebufferMs);
loadControl = loadBuilder.build();

exoPlayer = new SimpleExoPlayer.Builder(context)
.setTrackSelector(trackSelector)
.setLoadControl(loadControl)
.build();
workManager = WorkManager.getInstance(context);
workerObserverMap = new HashMap<>();

Expand Down Expand Up @@ -915,3 +932,4 @@ public int hashCode() {
}



Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

import androidx.annotation.NonNull;

import java.util.HashMap;
import java.util.Map;

import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
Expand All @@ -27,9 +30,6 @@
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.view.TextureRegistry;

import java.util.HashMap;
import java.util.Map;

/**
* Android platform implementation of the VideoPlayerPlugin.
*/
Expand Down Expand Up @@ -73,6 +73,10 @@ public class BetterPlayerPlugin implements FlutterPlugin, ActivityAware, MethodC
public static final String HEADER_PARAMETER = "header_";
public static final String FILE_PATH_PARAMETER = "filePath";
public static final String ACTIVITY_NAME_PARAMETER = "activityName";
public static final String MIN_BUFFER_MS = "minBufferMs";
public static final String MAX_BUFFER_MS = "maxBufferMs";
public static final String BUFFER_FOR_PLAYBACK_MS = "bufferForPlaybackMs";
public static final String BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS = "bufferForPlaybackAfterRebufferMs";
public static final String CACHE_KEY_PARAMETER = "cacheKey";


Expand Down Expand Up @@ -147,7 +151,6 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
return;
}


switch (call.method) {
case INIT_METHOD:
disposeAllPlayers();
Expand All @@ -159,9 +162,22 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
EventChannel eventChannel =
new EventChannel(
flutterState.binaryMessenger, EVENTS_CHANNEL + handle.id());
CustomDefaultLoadControl customDefaultLoadControl = null;
if (call.hasArgument(MIN_BUFFER_MS) && call.hasArgument(MAX_BUFFER_MS) &&
call.hasArgument(BUFFER_FOR_PLAYBACK_MS) &&
call.hasArgument(BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS)) {

customDefaultLoadControl =
new CustomDefaultLoadControl(call.argument(MIN_BUFFER_MS),
call.argument(MAX_BUFFER_MS),
call.argument(BUFFER_FOR_PLAYBACK_MS),
call.argument(BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS)
);
}

BetterPlayer player =
new BetterPlayer(flutterState.applicationContext, eventChannel, handle, result);
new BetterPlayer(flutterState.applicationContext, eventChannel, handle,
customDefaultLoadControl, result);

videoPlayers.put(handle.id(), player);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public Result doWork() {
if (cacheKey != null && cacheKey.length() > 0) {
dataSpec = dataSpec.buildUpon().setKey(cacheKey).build();
}

CacheDataSourceFactory cacheDataSourceFactory =
new CacheDataSourceFactory(mContext, maxCacheSize, maxCacheFileSize, dataSourceFactory);

Expand Down Expand Up @@ -98,7 +98,11 @@ public Result doWork() {

@Override
public void onStopped() {
mCacheWriter.cancel();
super.onStopped();
try {
mCacheWriter.cancel();
super.onStopped();
} catch (Exception exception) {
Log.e(TAG, exception.toString());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.jhomlala.better_player;

import com.google.android.exoplayer2.DefaultLoadControl;

class CustomDefaultLoadControl {
/**
* The default minimum duration of media that the player will attempt to ensure is buffered
* at all times, in milliseconds.
**/
public final int minBufferMs;

/**
* The default maximum duration of media that the player will attempt to buffer, in milliseconds.
**/
public final int maxBufferMs;

/**
* The default duration of media that must be buffered for playback to start or resume following
* a user action such as a seek, in milliseconds.
**/
public final int bufferForPlaybackMs;

/**
* he default duration of media that must be buffered for playback to resume after a rebuffer,
* in milliseconds. A rebuffer is defined to be caused by buffer depletion rather than a user
* action.
**/
public final int bufferForPlaybackAfterRebufferMs;

CustomDefaultLoadControl() {
this.minBufferMs = DefaultLoadControl.DEFAULT_MIN_BUFFER_MS;
this.maxBufferMs = DefaultLoadControl.DEFAULT_MAX_BUFFER_MS;
this.bufferForPlaybackMs = DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS;
this.bufferForPlaybackAfterRebufferMs =
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS;

}

CustomDefaultLoadControl(
Integer minBufferMs,
Integer maxBufferMs,
Integer bufferForPlaybackMs,
Integer bufferForPlaybackAfterRebufferMs
) {
this.minBufferMs = minBufferMs != null ? minBufferMs : DefaultLoadControl.DEFAULT_MIN_BUFFER_MS;
this.maxBufferMs = maxBufferMs != null ? maxBufferMs : DefaultLoadControl.DEFAULT_MAX_BUFFER_MS;
this.bufferForPlaybackMs = bufferForPlaybackMs != null ? bufferForPlaybackMs :
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS;
this.bufferForPlaybackAfterRebufferMs = bufferForPlaybackAfterRebufferMs != null ?
bufferForPlaybackAfterRebufferMs :
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS;
}
}
Binary file added example/assets/eleisure.cer
Binary file not shown.
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c

COCOAPODS: 1.10.0
COCOAPODS: 1.10.1
Loading

0 comments on commit 569f61a

Please sign in to comment.