在胶子应用程序中嵌入原生视频视图

时间:2016-11-21 11:30:32

标签: javafx gluon javafxports gluon-mobile

我应该为iOS和Android编写应用程序,有时会在屏幕的一部分上显示自定义的视频播放器。我必须能够控制它(寻找,播放,暂停,设定速度,选择视频......)。我知道Gluon尚不支持此类媒体。

但是可以在XCode和Android Studio中编写这样的东西并以某种方式将其嵌入到Gluon应用程序中吗?

2 个答案:

答案 0 :(得分:1)

遵循Gluon Charm Down library中的设计模式,这可能是VideoService的基本Android实现。

它基于此tutorial,适用于JavaFX使用的当前SurfaceView。它将创建一个TextureView,它将放置在屏幕中央,位于当前视图的顶部,占据其宽度的95%。

使用IDE的Gluon插件,创建一个单视图项目。

  1. 将这两个类放在源包,包com.gluonhq.charm.down.plugins
  2. 视频服务界面

    package com.gluonhq.charm.down.plugins;
    
    public interface VideoService {
        void play(String videoName);
        void stop();
        void pause();
        void resume();
    }
    

    VideoServiceFactory类

    package com.gluonhq.charm.down.plugins;
    
    import com.gluonhq.charm.down.DefaultServiceFactory;
    
    public class VideoServiceFactory extends DefaultServiceFactory<VideoService> {
    
        public VideoServiceFactory() {
            super(VideoService.class);
        }
    
    }
    
    1. Android程序包:将此类放在Android / Java包中,包com.gluonhq.charm.down.plugins.android
    2. AndroidVideoService类

      package com.gluonhq.charm.down.plugins.android;
      
      import android.content.Context;
      import android.content.res.AssetFileDescriptor;
      import android.graphics.SurfaceTexture;
      import android.media.MediaMetadataRetriever;
      import android.media.MediaPlayer;
      import android.util.DisplayMetrics;
      import android.util.Log;
      import android.view.Surface;
      import android.view.TextureView;
      import android.view.WindowManager;
      import android.widget.RelativeLayout;
      import com.gluonhq.charm.down.plugins.VideoService;
      import java.io.IOException;
      import javafxports.android.FXActivity;
      
      public class AndroidVideoService implements VideoService, TextureView.SurfaceTextureListener {
          private static final String TAG = AndroidVideoService.class.getName();
          private MediaPlayer mMediaPlayer;
          private String videoName;
      
          private final RelativeLayout relativeLayout;
          private final TextureView textureView;
          private final DisplayMetrics displayMetrics;
      
          public AndroidVideoService() {
              displayMetrics = new DisplayMetrics();
              WindowManager windowManager = (WindowManager) FXActivity.getInstance().getSystemService(Context.WINDOW_SERVICE);
              windowManager.getDefaultDisplay().getMetrics(displayMetrics);
      
              relativeLayout = new RelativeLayout(FXActivity.getInstance());
      
              textureView = new TextureView(FXActivity.getInstance());
              textureView.setSurfaceTextureListener(this);
              relativeLayout.addView(textureView);
          }
      
          @Override
          public void play(String videoName) {
              this.videoName = videoName;
              stop();
              FXActivity.getInstance().runOnUiThread(() -> {
                  FXActivity.getViewGroup().addView(relativeLayout);
              });
          }
      
          @Override
          public void stop() {
              if (mMediaPlayer != null) {
                  mMediaPlayer.stop();
                  mMediaPlayer.release();
                  mMediaPlayer = null;
              }
              if (relativeLayout != null) {
                  FXActivity.getInstance().runOnUiThread(() -> {
                      FXActivity.getViewGroup().removeView(relativeLayout);
                  });
              }
          }
      
          @Override
          public void pause() {
              if (mMediaPlayer != null) {
                  mMediaPlayer.pause();
              }
          }
      
          @Override
          public void resume() {
              if (mMediaPlayer != null) { 
                  mMediaPlayer.start();
              }
          }
      
          @Override
          public void onSurfaceTextureAvailable(SurfaceTexture st, int i, int i1) {
              Surface surface = new Surface(st);
              try {
                  AssetFileDescriptor afd = FXActivity.getInstance().getAssets().openFd(videoName);
                  calculateVideoSize(afd);
                  mMediaPlayer = new MediaPlayer();
                  mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
                  mMediaPlayer.setSurface(surface);
                  mMediaPlayer.setLooping(true);
                  mMediaPlayer.prepareAsync();
                  mMediaPlayer.setOnPreparedListener(mediaPlayer -> mediaPlayer.start());
      
              } catch (IllegalArgumentException | SecurityException | IllegalStateException | IOException e) {
                  Log.d(TAG, e.getMessage());
              }
          }
      
          @Override public void onSurfaceTextureSizeChanged(SurfaceTexture st, int i, int i1) { }
          @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture st) { return true; }
          @Override public void onSurfaceTextureUpdated(SurfaceTexture st) { }
      
          private void calculateVideoSize(AssetFileDescriptor afd) {
              try {
                  MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
                  metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
                  String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
                  String width = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
                  double factor = Double.parseDouble(width) > 0 ? Double.parseDouble(height) / Double.parseDouble(width) : 1d;
                  // 95% screen width
                  RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int) (0.95 * displayMetrics.widthPixels), 
                          (int) (0.95 * displayMetrics.widthPixels * factor));
                  lp.addRule(RelativeLayout.CENTER_IN_PARENT);
                  textureView.setLayoutParams(lp);
              } catch (NumberFormatException e) {
                  Log.d(TAG, e.getMessage());
              }
          }
      }
      
      1. 样品
      2. 将视频文件放在android / assets文件夹中,例如big_buck_bunny.mp4,可以从here下载。

        <强> BasicView

        public class BasicView extends View {
        
            private boolean paused;
        
            public BasicView(String name) {
                super(name);
            }
        
            @Override
            protected void updateAppBar(AppBar appBar) {
                appBar.setNavIcon(MaterialDesignIcon.MENU.button());
                appBar.setTitleText("Video View");
                // big_buck_bunny.mp4 video in src/android/assets:
                Services.get(VideoService.class).ifPresent(video -> {
                    appBar.getActionItems().add(MaterialDesignIcon.PLAY_ARROW.button(e -> video.play("big_buck_bunny.mp4")));
                    appBar.getActionItems().add(MaterialDesignIcon.PAUSE.button(e -> {
                        if (!paused) {
                            video.pause();
                            paused = true;
                        } else {
                            video.resume();
                            paused = false;
                        }
                    }));
                    appBar.getActionItems().add(MaterialDesignIcon.STOP.button(e -> video.stop()));
                });
            }
        
        }
        

        在您的Android设备上部署并测试:

        请注意,TextureView将位于顶部,直到您按下停止按钮将其删除。

答案 1 :(得分:0)

以下示例中使用了原生视频播放器(或者在这种情况下是&#34;预览&#34;视频的方法):

https://gist.github.com/bgmf/d87a2bac0a5623f359637a3da334f980

除了一些先决条件,代码如下所示:

package my.application;

import ch.cnlab.disentis.util.Constants;
import org.robovm.apple.foundation.*;
import org.robovm.apple.uikit.UIApplication;
import org.robovm.apple.uikit.UIDocumentInteractionController;
import org.robovm.apple.uikit.UIDocumentInteractionControllerDelegateAdapter;
import org.robovm.apple.uikit.UIViewController;

import java.io.File;
import java.util.logging.Logger;

public class NativeVideoServiceIOS extends PathHelperIOS implements NativeVideoService {
    private static final Logger LOG = Logger.getLogger(NativeVideoServiceIOS.class.getName());

    public NativeVideoServiceIOS() {
        LOG.warning("Initialized Native Video Service with path: " + this.pathBase);
    }

    @Override
    public void triggerPlatformApp(String filename) {
        String fullfile = pathBase.getAbsolutePath() + filename;
        NSURL url = new NSURL(NSURLScheme.File, "", fullfile);
        UIDocumentInteractionController popup = new UIDocumentInteractionController(url);
        popup.setDelegate(new UIDocumentInteractionControllerDelegateAdapter() {
            @Override
            public UIViewController getViewControllerForPreview(UIDocumentInteractionController controller) {
                return UIApplication.getSharedApplication()
                        .getWindows().first().getRootViewController();
            }
        });
        popup.presentPreview(true);
    }

}