Skip to content

Commit

Permalink
Add vlc options from flutter (REDO) (#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
mitchross authored Jul 31, 2020
1 parent d0ace3e commit 5551e02
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 41 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.0.4
* Updates MobileVLC to allow for options as flags and hardware acceleration/
credits to pharshdev (https://github.com/pharshdev) and Mitch Ross (https://github.com/mitchross)

## 3.0.3
* Updates MobileVLC to fix a bug on iOS with Seek Time. See (https://github.com/solid-software/flutter_vlc_player/issues/72). Also adds seek bar to example player for demonstration purposes.
credits to Mitch Ross (https://github.com/mitchross)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
import android.view.Surface;
import android.view.TextureView;
import android.view.View;

import androidx.annotation.NonNull;

import io.flutter.plugin.common.*;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.view.TextureRegistry;

import org.videolan.libvlc.IVLCVout;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.Media;
Expand All @@ -27,6 +30,10 @@ class FlutterVideoView implements PlatformView, MethodChannel.MethodCallHandler,

// Silences player log output.
private static final boolean DISABLE_LOG_OUTPUT = true;
private static final int HW_ACCELERATION_AUTOMATIC = -1;
private static final int HW_ACCELERATION_DISABLED = 0;
private static final int HW_ACCELERATION_DECODING = 1;
private static final int HW_ACCELERATION_FULL = 2;

final PluginRegistry.Registrar registrar;
private final MethodChannel methodChannel;
Expand All @@ -52,34 +59,34 @@ public FlutterVideoView(Context context, PluginRegistry.Registrar _registrar, Bi
eventChannel = new EventChannel(messenger, "flutter_video_plugin/getVideoEvents_" + id);

eventChannel.setStreamHandler(
new EventChannel.StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink sink) {
eventSink.setDelegate(sink);
}
new EventChannel.StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink sink) {
eventSink.setDelegate(sink);
}

@Override
public void onCancel(Object o) {
eventSink.setDelegate(null);
@Override
public void onCancel(Object o) {
eventSink.setDelegate(null);
}
}
}
);

TextureRegistry.SurfaceTextureEntry textureEntry = registrar.textures().createSurfaceTexture();
textureView = new TextureView(context);
textureView.setSurfaceTexture(textureEntry.surfaceTexture());
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener(){
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {

boolean wasPaused = false;

@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
if(vout == null) return;
if (vout == null) return;

vout.setVideoSurface(new Surface(textureView.getSurfaceTexture()), null);
vout.attachViews();
textureView.forceLayout();
if(wasPaused){
if (wasPaused) {
mediaPlayer.play();
wasPaused = false;
}
Expand All @@ -92,15 +99,15 @@ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int h

@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
if(playerDisposed){
if(mediaPlayer != null) {
if (playerDisposed) {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
return true;
}else{
if(mediaPlayer != null && vout != null) {
} else {
if (mediaPlayer != null && vout != null) {
mediaPlayer.pause();
wasPaused = true;
vout.detachViews();
Expand All @@ -127,8 +134,8 @@ public View getView() {

@Override
public void dispose() {
if(mediaPlayer != null) mediaPlayer.stop();
if(vout != null) vout.detachViews();
if (mediaPlayer != null) mediaPlayer.stop();
if (vout != null) vout.detachViews();
playerDisposed = true;
}

Expand All @@ -144,15 +151,7 @@ public void onMethodCall(MethodCall methodCall, @NonNull MethodChannel.Result re
textureView = new TextureView(context);
}

ArrayList<String> options = new ArrayList<>();
options.add("--no-drop-late-frames");
options.add("--no-skip-frames");
options.add("--rtsp-tcp");

if(DISABLE_LOG_OUTPUT) {
// Silence player log output.
options.add("--quiet");
}
ArrayList<String> options = methodCall.argument("options");

libVLC = new LibVLC(context, options);
mediaPlayer = new MediaPlayer(libVLC);
Expand All @@ -166,21 +165,34 @@ public void onMethodCall(MethodCall methodCall, @NonNull MethodChannel.Result re

String initStreamURL = methodCall.argument("url");
Media media = new Media(libVLC, Uri.parse(initStreamURL));
mediaPlayer.setMedia(media);

int hardwareAcceleration = methodCall.argument("hwAcc");
if (hardwareAcceleration != HW_ACCELERATION_AUTOMATIC)
if (hardwareAcceleration == HW_ACCELERATION_DISABLED) {
media.setHWDecoderEnabled(false, false);
} else if (hardwareAcceleration == HW_ACCELERATION_FULL || hardwareAcceleration == HW_ACCELERATION_DECODING) {
media.setHWDecoderEnabled(true, true);
if (hardwareAcceleration == HW_ACCELERATION_DECODING) {
media.addOption(":no-mediacodec-dr");
media.addOption(":no-omxil-dr");
}
}

media.addOption(":input-fast-seek");
mediaPlayer.setMedia(media);
result.success(null);
break;
case "dispose":
this.dispose();
break;
case "changeURL":
if(libVLC == null) result.error("VLC_NOT_INITIALIZED", "The player has not yet been initialized.", false);
if (libVLC == null)
result.error("VLC_NOT_INITIALIZED", "The player has not yet been initialized.", false);

mediaPlayer.stop();
String newURL = methodCall.argument("url");
Media newMedia = new Media(libVLC, Uri.parse(newURL));
mediaPlayer.setMedia(newMedia);

result.success(null);
break;
case "getSnapshot":
Expand All @@ -198,9 +210,9 @@ public void onMethodCall(MethodCall methodCall, @NonNull MethodChannel.Result re
case "setPlaybackState":

String playbackState = methodCall.argument("playbackState");
if(playbackState == null) result.success(null);
if (playbackState == null) result.success(null);

switch(playbackState){
switch (playbackState) {
case "play":
textureView.forceLayout();
mediaPlayer.play();
Expand Down Expand Up @@ -251,7 +263,7 @@ public void onEvent(MediaPlayer.Event event) {
int width = 0;

Media.VideoTrack currentVideoTrack = (Media.VideoTrack) mediaPlayer.getMedia().getTrack(
mediaPlayer.getVideoTrack()
mediaPlayer.getVideoTrack()
);
if (currentVideoTrack != null) {
height = currentVideoTrack.height;
Expand All @@ -277,7 +289,7 @@ public void onEvent(MediaPlayer.Event event) {
eventObject.put("value", false);
eventObject.put("reason", "EndReached");
eventSink.success(eventObject);

case MediaPlayer.Event.Vout:
vout.setWindowSize(textureView.getWidth(), textureView.getHeight());
break;
Expand Down
12 changes: 10 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,16 @@ class MyAppScaffoldState extends State<MyAppScaffold> {
child: new VlcPlayer(
aspectRatio: 16 / 9,
url:
"http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_60fps_normal.mp4",
"https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
controller: _videoViewController,
// Play with vlc options
options: [
'--quiet',
'--no-drop-late-frames',
'--no-skip-frames',
'--rtsp-tcp'
],
hwAcc: HwAcc.DISABLED, // or {HwAcc.AUTO, HwAcc.DECODING, HwAcc.FULL}
placeholder: Container(
height: 250.0,
child: Row(
Expand All @@ -98,7 +106,7 @@ class MyAppScaffoldState extends State<MyAppScaffold> {
child: new VlcPlayer(
aspectRatio: 16 / 9,
url:
"https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
"http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_60fps_normal.mp4",
controller: _videoViewController2,
placeholder: Container(
height: 250.0,
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies:

# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
cupertino_icons: ^0.1.3

dev_dependencies:
flutter_test:
Expand Down
39 changes: 36 additions & 3 deletions lib/flutter_vlc_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,25 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';

enum PlayingState { STOPPED, BUFFERING, PLAYING }
enum HwAcc { AUTO, DISABLED, DECODING, FULL }

int getHwAcc({@required HwAcc hwAcc}) {
switch (hwAcc) {
case HwAcc.DISABLED:
return 0;
break;
case HwAcc.DECODING:
return 1;
break;
case HwAcc.FULL:
return 2;
break;
case HwAcc.AUTO:
default:
return -1;
break;
}
}

class Size {
final int width;
Expand All @@ -23,6 +42,8 @@ class Size {

class VlcPlayer extends StatefulWidget {
final double aspectRatio;
final HwAcc hwAcc;
final List<String> options;
final String url;
final Widget placeholder;
final VlcPlayerController controller;
Expand All @@ -42,6 +63,13 @@ class VlcPlayer extends StatefulWidget {
/// [VlcPlayerController.setStreamUrl] method so this can be changed at any time.
@required this.url,

/// Set hardware acceleration for player. Default is Automatic.
this.hwAcc,

/// Adds options to vlc. For more [https://wiki.videolan.org/VLC_command-line_help] If nothing is provided,
/// vlc will run without any options set.
this.options,

/// Before the platform view has initialized, this placeholder will be rendered instead of the video player.
/// This can simply be a [CircularProgressIndicator] (see the example.)
this.placeholder,
Expand Down Expand Up @@ -121,7 +149,7 @@ class _VlcPlayerState extends State<VlcPlayer>
// Once the controller has clients registered, we're good to register
// with LibVLC on the platform side.
if (_controller.hasClients) {
await _controller._initialize(widget.url);
await _controller._initialize( widget.url,widget.hwAcc, widget.options,);
}
}

Expand Down Expand Up @@ -245,10 +273,15 @@ class VlcPlayerController {
_eventHandlers.forEach((handler) => handler());
}

Future<void> _initialize(String url) async {
Future<void> _initialize(
String url,[HwAcc hwAcc, List<String> options]) async {
//if(initialized) throw new Exception("Player already initialized!");

await _methodChannel.invokeMethod("initialize", {'url': url});
await _methodChannel.invokeMethod("initialize", {
'url': url,
'hwAcc': getHwAcc(hwAcc: hwAcc),
'options': options ?? []
});
_position = 0;

_eventChannel.receiveBroadcastStream().listen((event) {
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: flutter_vlc_player
description: A VLC-powered alternative to Flutter's video_player. Supports multiple players on one screen.
version: 3.0.3
version: 3.0.4
homepage: https://github.com/solid-software/flutter_vlc_player

environment:
Expand Down

0 comments on commit 5551e02

Please sign in to comment.