【问题标题】:How do you Fullscreen RTSP Stream in Android LibVLC?你如何在 Android LibVLC 中全屏显示 RTSP 流?
【发布时间】:2018-10-31 23:23:01
【问题描述】:

我正在使用 mrmaffen 的 VLC-ANDROID-SDK 开发 RTSP 流媒体应用。 https://github.com/mrmaffen/vlc-android-sdk

我在让它工作和运行良好方面取得了很大的成功,但我遇到的一个我似乎无法动摇的问题是让它在 SurfaceView 上全屏显示视频源,甚至就在 SurfaceView 的中心。

这是我得到的:

http://s1378.photobucket.com/user/Jo_Han_Solo/media/Screenshot_20171214-125504_zps437k1kw2.png.html?filters[user]=146993343&filters[recent]=1&sort=1&o=1

黑色窗口是屏幕的总大小,我希望该视频填满屏幕并希望始终从中心填充,但我不知道该怎么做。

任何人都有过类似的经历并且知道如何解决它?

【问题讨论】:

    标签: android android-studio fullscreen rtsp libvlc


    【解决方案1】:

    我有点解决了这个问题,但以一种有点狡猾的方式,它远未完成,但考虑到缺乏关于该主题的知识和信息,我认为这可能暂时对某人有所帮助。

    1. 找出您的屏幕尺寸。
    2. 设置最终的 IVLCOut 以合并屏幕尺寸。
    3. 将 setScale 调整为“全屏”视频流。

    解释每个任务:

    1. 设置你的全局变量:

      public class SingleStreamView extends AppCompatActivity implements 
      IVLCVout.Callback {
      
      public int mHeight;
      public int mWidth;
      

    其次,在 onCreate 任务中找到您设备的屏幕尺寸:

        DisplayMetrics displayMetrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
            mHeight = displayMetrics.heightPixels;
            mWidth = displayMetrics.widthPixels;
    

    2。 然后转到您的“CreatePlayer”事件和您设置视频输出的位置:

        // Set up video output
            final IVLCVout vout = mMediaPlayer.getVLCVout();
            vout.setVideoView(mSurface);
            vout.setWindowSize(mWidth,mHeight);
            vout.addCallback(this);
            vout.attachViews();
    

    使它在我的表面居中的获胜线是“vout.setWindowSize(mWidth,mHeight);”

    然后我简单地使用 setscale 选项“全屏”播放视频。也就是说,这是一种hack的方法,我想尝试找出一种方法来获取编解码器信息,以便动态设置视频的比例,并且自动设置这种方式全屏各种尺寸的视频流到任何尺寸的屏幕,但目前这适用于已知的视频流分辨率,它会自动调整到您手机的屏幕尺寸。

    无论哪种方式,我发现对于三星 Galaxy s8,640x480p RTSP 流的良好缩放因子是 1.8。编码如下:

            Media m = new Media(libvlc, Uri.parse(RTSP_ADDRESS));
            m.setHWDecoderEnabled(true,false);
            m.addOption(":network-caching=100");
            m.addOption(":clock-jitter=0");
            m.addOption(":clock-synchro=0");
            m.addOption(":fullscreen");
            mMediaPlayer.setMedia(m);
            mMediaPlayer.setAspectRatio("16:9");
            mMediaPlayer.setScale(1.8f);
            mMediaPlayer.play();
    

    你在哪里得到“mMediaPlayer.setScale(1.8f);”

    希望这对某人有所帮助!

    【讨论】:

      【解决方案2】:

      您的解决方案似乎很有趣,但我也面临同样的问题,我似乎(还)无法用您的方法解决。

      我目前所获得的屏幕截图可以在以下位置看到: https://photos.app.goo.gl/9nKo22Mkc2SZq4SK9

      我还想(垂直)在 Samsung-XCover4(720x1280 像素)和最小分辨率为 320x480 的设备上以横向/纵向模式将 rtsp-video-stream 居中。我希望它运行的最低 Android SDK 版本是 API-22 (Android 5.1.1)。 我让(嵌入式)VLC 播放器工作的 libvlc 代码基于 'de.mrmaffen:libvlc-android:2.1.12@aar'。

      鉴于上述“要求”,您可以在屏幕截图中看到以下行为。前两个屏幕截图位于 Samsung-XCover4 (720x1280) 上,您可以在其中看到 device-orientation=landscape 剪辑视频并且不缩放,而第 3 和第 4 个屏幕截图显示相同的视频流不跟随在具有小分辨率的设备上使用 SURFACE_BEST_FIT 方法(请参阅下面的代码以获取解释)。 我很想看到一个 updateVideoSurfaces 来处理设备方向的变化,或者至少在启动时显示整个视频。

      我的 VLC-video-player(垂直 LinearLayout 的一部分)的布局如下:

      <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="0dp"
          android:layout_weight="0.3"
          android:layout_marginBottom="8dp"
          android:layout_marginEnd="8dp"
          android:layout_marginStart="8dp"
          android:layout_marginTop="8dp"
          android:orientation="vertical">
      
          <FrameLayout
              android:id="@+id/video_surface_frame"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_gravity="center"
              android:foregroundGravity="clip_horizontal|clip_vertical"
              tools:ignore="true">
      
              <ViewStub
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:layout="@layout/surface_view"
                  android:id="@+id/surface_stub" />
      
              <ViewStub
                  android:layout_width="1dp"
                  android:layout_height="1dp"
                  android:layout="@layout/surface_view"
                  android:id="@+id/subtitles_surface_stub" />
      
              <ViewStub
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:layout="@layout/texture_view"
                  android:id="@+id/texture_stub" />
      
          </FrameLayout>
      
      </LinearLayout>
      

      我从 de.mrmaffen 获得的示例代码使用了一个 updateVideoSurfaces(参见下面的 java 代码),它使用了一些 SURFACE_XX 方法,在我看来,这些方法涵盖了具有不同设备方向和分辨率的所有场景。

      出于某种原因,我无法弄清楚为什么这不起作用,并且我怀疑我用于播放器的布局(FrameLayout/ViewStub's)可能会导致问题。

      我想知道您是否可以阐明一些方向,以确保视频流将自动缩放/居中于任何设备方向/分辨率。

      我使用的播放器代码如下:

      package com.testing.vlc2player;
      
      import ...
      
      public class VLC2PlayerActivity extends AppCompatActivity implements IVLCVout.OnNewVideoLayoutListener,
              IVLCVout.Callback {
      
          private static final Logger log = LoggerFactory.getLogger(VLC2PlayerActivity.class);
      
          private static final boolean USE_SURFACE_VIEW = true;
          private static final boolean ENABLE_SUBTITLES = false;
          private static final int SURFACE_BEST_FIT = 0;
          private static final int SURFACE_FIT_SCREEN = 1;
          private static final int SURFACE_FILL = 2;
          private static final int SURFACE_16_9 = 3;
          private static final int SURFACE_4_3 = 4;
          private static final int SURFACE_ORIGINAL = 5;
          private static final int CURRENT_SIZE = SURFACE_BEST_FIT;
      
          private FrameLayout mVideoSurfaceFrame = null;
          private SurfaceView mVideoSurface = null;
          private SurfaceView mSubtitlesSurface = null;
          private TextureView mVideoTexture = null;
          private View mVideoView = null;
      
          private final Handler mHandler = new Handler();
          private View.OnLayoutChangeListener mOnLayoutChangeListener = null;
      
          private LibVLC mLibVLC = null;
          private MediaPlayer mMediaPlayer = null;
          private int mVideoHeight = 0;
          private int mVideoWidth = 0;
          private int mVideoVisibleHeight = 0;
          private int mVideoVisibleWidth = 0;
          private int mVideoSarNum = 0;
          private int mVideoSarDen = 0;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_video_player);
      
              setupVLCLayout();
          }
      
          private void setupVLCLayout() {
              log.debug("...");
              final ArrayList<String> args = new ArrayList<>();
              args.add("-vvv");
              mLibVLC = new LibVLC(this, args);
              mMediaPlayer = new MediaPlayer(mLibVLC);
      
              mVideoSurfaceFrame = findViewById(R.id.video_surface_frame);
              if (USE_SURFACE_VIEW) {
                  ViewStub stub = findViewById(R.id.surface_stub);
                  mVideoSurface = (SurfaceView) stub.inflate();
                  if (ENABLE_SUBTITLES) {
                      stub = findViewById(R.id.subtitles_surface_stub);
                      mSubtitlesSurface = (SurfaceView) stub.inflate();
                      mSubtitlesSurface.setZOrderMediaOverlay(true);
                      mSubtitlesSurface.getHolder().setFormat(PixelFormat.TRANSLUCENT);
                  }
                  mVideoView = mVideoSurface;
              } else {
                  ViewStub stub = findViewById(R.id.texture_stub);
                  mVideoTexture = (TextureView) stub.inflate();
                  mVideoView = mVideoTexture;
              }
          }
      
          @Override
          protected void onDestroy() {
              super.onDestroy();
              mMediaPlayer.release();
              mLibVLC.release();
          }
      
          @Override
          protected void onStart() {
              super.onStart();
              final IVLCVout vlcVout = mMediaPlayer.getVLCVout();
              if (mVideoSurface != null) {
                  vlcVout.setVideoView(mVideoSurface);
                  if (mSubtitlesSurface != null) {
                      vlcVout.setSubtitlesView(mSubtitlesSurface);
                  }
              } else {
                  vlcVout.setVideoView(mVideoTexture);
              }
              vlcVout.attachViews(this);
      
              String url = getString(R.string.videoURL);
              Uri uri = Uri.parse(url);
              final Media media = new Media(mLibVLC, uri);
              mMediaPlayer.setMedia(media);
              media.release();
              mMediaPlayer.play();
      
              if (mOnLayoutChangeListener == null) {
                  mOnLayoutChangeListener = new View.OnLayoutChangeListener() {
                      private final Runnable mRunnable = new Runnable() {
                          @Override
                          public void run() {
                              updateVideoSurfaces();
                          }
                      };
                      @Override
                      public void onLayoutChange(View v, int left, int top, int right,
                                                 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                          if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) {
                              mHandler.removeCallbacks(mRunnable);
                              mHandler.post(mRunnable);
                          }
                      }
                  };
              }
              mVideoSurfaceFrame.addOnLayoutChangeListener(mOnLayoutChangeListener);
          }
      
          @Override
          protected void onStop() {
              super.onStop();
              if (mOnLayoutChangeListener != null) {
                  mVideoSurfaceFrame.removeOnLayoutChangeListener(mOnLayoutChangeListener);
                  mOnLayoutChangeListener = null;
              }
              mMediaPlayer.stop();
              mMediaPlayer.getVLCVout().detachViews();
          }
      
          private void changeMediaPlayerLayout(int displayW, int displayH) {
              log.debug("displayW={}, displayH={}", displayW, displayH);
              /* Change the video placement using the MediaPlayer API */
              int dispWd = displayW;
              int dispHt = displayH;
              dispWd = mVideoSurface.getWidth();  //Note: we do NOT want to use the entire display!
              dispHt = mVideoSurface.getHeight();
              switch (CURRENT_SIZE) {
                  case SURFACE_BEST_FIT:
                      mMediaPlayer.setAspectRatio(null);
                      mMediaPlayer.setScale(0);
                      break;
                  case SURFACE_FIT_SCREEN:
                  case SURFACE_FILL: {
                      Media.VideoTrack vtrack = mMediaPlayer.getCurrentVideoTrack();
                      if (vtrack == null) {
                          return;
                      }
                      final boolean videoSwapped = vtrack.orientation == Media.VideoTrack.Orientation.LeftBottom
                              || vtrack.orientation == Media.VideoTrack.Orientation.RightTop;
                      if (CURRENT_SIZE == SURFACE_FIT_SCREEN) {
                          int videoW = vtrack.width;
                          int videoH = vtrack.height;
                          if (videoSwapped) {
                              int swap = videoW;
                              videoW = videoH;
                              videoH = swap;
                          }
                          if (vtrack.sarNum != vtrack.sarDen) {
                              videoW = videoW * vtrack.sarNum / vtrack.sarDen;
                          }
                          float ar = videoW / (float) videoH;
                          float dar = dispWd / (float) dispHt;
                          //noinspection unused
                          float scale;
                          if (dar >= ar) {
                              scale = dispWd / (float) videoW; /* horizontal */
                          } else {
                              scale = dispHt / (float) videoH; /* vertical */
                          }
                          log.debug("scale={}", scale);
                          mMediaPlayer.setScale(scale);
                          mMediaPlayer.setAspectRatio(null);
                      } else {
                          mMediaPlayer.setScale(0);
                          mMediaPlayer.setAspectRatio(!videoSwapped ? ""+dispWd+":"+dispHt
                                  : ""+dispHt+":"+dispWd);
                      }
                      break;
                  }
                  case SURFACE_16_9:
                      mMediaPlayer.setAspectRatio("16:9");
                      mMediaPlayer.setScale(0);
                      break;
                  case SURFACE_4_3:
                      mMediaPlayer.setAspectRatio("4:3");
                      mMediaPlayer.setScale(0);
                      break;
                  case SURFACE_ORIGINAL:
                      mMediaPlayer.setAspectRatio(null);
                      mMediaPlayer.setScale(1);
                      break;
              }
          }
      
          private void updateVideoSurfaces() {
              log.debug("...");
              int sw = getWindow().getDecorView().getWidth();
              int sh = getWindow().getDecorView().getHeight();
              // sanity check
              if (sw * sh == 0) {
                  log.error("Invalid surface size");
                  return;
              }
      
              mMediaPlayer.getVLCVout().setWindowSize(sw, sh);
      
              ViewGroup.LayoutParams lp = mVideoView.getLayoutParams();
              if (mVideoWidth * mVideoHeight == 0) {
                  /* Case of OpenGL vouts: handles the placement of the video using MediaPlayer API */
                  lp.width  = ViewGroup.LayoutParams.MATCH_PARENT;
                  lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
                  mVideoView.setLayoutParams(lp);
                  lp = mVideoSurfaceFrame.getLayoutParams();
                  lp.width  = ViewGroup.LayoutParams.MATCH_PARENT;
                  lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
                  mVideoSurfaceFrame.setLayoutParams(lp);
                  changeMediaPlayerLayout(sw, sh);
                  return;
              }
      
              if (lp.width == lp.height && lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
                  /* We handle the placement of the video using Android View LayoutParams */
                  mMediaPlayer.setAspectRatio(null);
                  mMediaPlayer.setScale(0);
              }
      
              double dw = sw, dh = sh;
              final boolean isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
      
              if (sw > sh && isPortrait || sw < sh && !isPortrait) {
                  dw = sh;
                  dh = sw;
              }
      
              // compute the aspect ratio
              double ar, vw;
              if (mVideoSarDen == mVideoSarNum) {
                  /* No indication about the density, assuming 1:1 */
                  vw = mVideoVisibleWidth;
                  ar = (double)mVideoVisibleWidth / (double)mVideoVisibleHeight;
              } else {
                  /* Use the specified aspect ratio */
                  vw = mVideoVisibleWidth * (double)mVideoSarNum / mVideoSarDen;
                  ar = vw / mVideoVisibleHeight;
              }
      
              // compute the display aspect ratio
              double dar = dw / dh;
      
              switch (CURRENT_SIZE) {
                  case SURFACE_BEST_FIT:
                      if (dar < ar) {
                          dh = dw / ar;
                      } else {
                          dw = dh * ar;
                      }
                      break;
                  case SURFACE_FIT_SCREEN:
                      if (dar >= ar) {
                          dh = dw / ar; /* horizontal */
                      } else {
                          dw = dh * ar; /* vertical */
                      }
                      break;
                  case SURFACE_FILL:
                      break;
                  case SURFACE_16_9:
                      ar = 16.0 / 9.0;
                      if (dar < ar) {
                          dh = dw / ar;
                      } else {
                          dw = dh * ar;
                      }
                      break;
                  case SURFACE_4_3:
                      ar = 4.0 / 3.0;
                      if (dar < ar) {
                          dh = dw / ar;
                      } else {
                          dw = dh * ar;
                      }
                      break;
                  case SURFACE_ORIGINAL:
                      dh = mVideoVisibleHeight;
                      dw = vw;
                      break;
              }
      
              // set display size
              lp.width  = (int) Math.ceil(dw * mVideoWidth / mVideoVisibleWidth);
              lp.height = (int) Math.ceil(dh * mVideoHeight / mVideoVisibleHeight);
              mVideoView.setLayoutParams(lp);
              if (mSubtitlesSurface != null) {
                  mSubtitlesSurface.setLayoutParams(lp);
              }
              // set frame size (crop if necessary)
              lp = mVideoSurfaceFrame.getLayoutParams();
              lp.width = (int) Math.floor(dw);
              lp.height = (int) Math.floor(dh);
              mVideoSurfaceFrame.setLayoutParams(lp);
      
              mVideoView.invalidate();
              if (mSubtitlesSurface != null) {
                  mSubtitlesSurface.invalidate();
              }
          }
      
          @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
          @Override
          public void onNewVideoLayout(IVLCVout vlcVout, int width, int height,
                                       int visibleWidth, int visibleHeight,
                                       int sarNum, int sarDen) {
              log.debug("...");
              mVideoWidth = width;
              mVideoHeight = height;
              mVideoVisibleWidth = visibleWidth;
              mVideoVisibleHeight = visibleHeight;
              mVideoSarNum = sarNum;
              mVideoSarDen = sarDen;
              updateVideoSurfaces();
          }
      
          @Override
          public void onSurfacesCreated(IVLCVout vlcVout) {
              log.debug("vlcVout={}", vlcVout);
          }
      
          /**
           * This callback is called when surfaces are destroyed.
           */
          public void onSurfacesDestroyed(IVLCVout vlcVout) {
              log.debug("vlcVout={}", vlcVout);
          }
      
          public void onStopClientMonitoring(View view) {
      //        log.info("UI -> Stop monitoring clientId= ...");
      //        onBackPressed();
              String androidSDKRelease = Build.VERSION.RELEASE;
              int androidSDKInt = Build.VERSION.SDK_INT;
              String androidInfo = String.format(Locale.getDefault(), "Android %s (Version %d)", androidSDKRelease, androidSDKInt);
              String appVersionName = BuildConfig.VERSION_NAME;
              String appName = getString(R.string.app_name);
              String appInfoTitle = String.format(getString(R.string.app_info_title), appName);
              String infoMsg = String.format(getString(R.string.app_info_message), appVersionName, androidInfo);
      
              new AlertDialog.Builder(this).setTitle(appInfoTitle)
                      .setMessage(infoMsg)
                      .setPositiveButton(getString(R.string.button_ok), new DialogInterface.OnClickListener() {
                          @Override
                          public void onClick(DialogInterface dialog, int which) {
                              // Dismiss dialog
                              dialog.dismiss();
                          }
                      })
                      .create()
                      .show();
          }
      }
      

      【讨论】:

      • 通过更改 updateVideoSurfaces() 方法找到解决方案: int sw = mVideoSurface.getWidth(); int sh = mVideoSurface.getHeight();
      猜你喜欢
      • 2015-01-14
      • 2017-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多