zoukankan      html  css  js  c++  java
  • Android基于libvlc 播发rtsp视频流

    使用libvlc 播放rtsp视频流的app demo.

    从官方vlc官方sample上修改而来,下载地址:https://code.videolan.org/videolan/libvlc-android-samples/tree/master/

    官方的sample是播放一个在安装包里面的.m4v 的卡通动画,稍作改动,就可以播放rtsp视频流了。(直接下载过来的工程无法使用,缺少 vlc的aar包,编译app也未配置好。个人配置好的包:https://download.csdn.net/download/u012459903/11049974)

    把demo里面的 

    final Media media = new Media(mLibVLC, getAssets().openFd(ASSET_FILENAME));
    改为

    final Media media = new Media(mLibVLC, Uri.parse("rtsp://192.168.43.233:10086/stream"));
    rtsp地址替换为自己的rtsp,去掉异常捕捉部分,可以在pc上用vlc播放器搭建一个进行测试。

    官方的主要源码:

    activity:

    /*****************************************************************************
    * JavaActivity.java
    *****************************************************************************
    * Copyright (C) 2016 VideoLAN
    * All rights reserved.
    *
    * This software may be modified and distributed under the terms
    * of the BSD license. See the LICENSE file for details.
    *****************************************************************************/

    package org.videolan.javasample;

    import android.annotation.TargetApi;
    import android.content.res.Configuration;
    import android.graphics.PixelFormat;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Handler;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.SurfaceView;
    import android.view.TextureView;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.ViewStub;
    import android.widget.FrameLayout;

    import org.videolan.libvlc.IVLCVout;
    import org.videolan.libvlc.LibVLC;
    import org.videolan.libvlc.Media;
    import org.videolan.libvlc.MediaPlayer;

    import java.io.IOException;
    import java.util.ArrayList;

    public class JavaActivity extends AppCompatActivity implements IVLCVout.OnNewVideoLayoutListener {
    private static final boolean USE_SURFACE_VIEW = true;
    private static final boolean ENABLE_SUBTITLES = true;
    private static final String TAG = "JavaActivity";
    private static final String ASSET_FILENAME = "bbb.m4v";
    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 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_main);

    final ArrayList<String> args = new ArrayList<>();
    args.add("-vvv");
    mLibVLC = new LibVLC(this, args);
    mMediaPlayer = new MediaPlayer(mLibVLC);

    mVideoSurfaceFrame = (FrameLayout) findViewById(R.id.video_surface_frame);
    if (USE_SURFACE_VIEW) {
    ViewStub stub = (ViewStub) findViewById(R.id.surface_stub);
    mVideoSurface = (SurfaceView) stub.inflate();
    if (ENABLE_SUBTITLES) {
    stub = (ViewStub) findViewById(R.id.subtitles_surface_stub);
    mSubtitlesSurface = (SurfaceView) stub.inflate();
    mSubtitlesSurface.setZOrderMediaOverlay(true);
    mSubtitlesSurface.getHolder().setFormat(PixelFormat.TRANSLUCENT);
    }
    mVideoView = mVideoSurface;
    }
    else
    {
    ViewStub stub = (ViewStub) 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);
    /*
    try {
    // final Media media = new Media(mLibVLC, getAssets().openFd(ASSET_FILENAME));
    final Media media = new Media(mLibVLC, Uri.parse("rtsp://192.168.43.14:10086/stream"));
    mMediaPlayer.setMedia(media);
    media.release();
    } catch (IOException e) {
    throw new RuntimeException("Invalid asset folder");
    }
    */
    final Media media = new Media(mLibVLC, Uri.parse("rtsp://192.168.43.233:10086/stream"));
    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) {
    /* Change the video placement using the MediaPlayer API */
    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 = displayW / (float) displayH;

    float scale;
    if (dar >= ar)
    scale = displayW / (float) videoW; /* horizontal */
    else
    scale = displayH / (float) videoH; /* vertical */
    mMediaPlayer.setScale(scale);
    mMediaPlayer.setAspectRatio(null);
    } else {
    mMediaPlayer.setScale(0);
    mMediaPlayer.setAspectRatio(!videoSwapped ? ""+displayW+":"+displayH
    : ""+displayH+":"+displayW);
    }
    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() {
    int sw = getWindow().getDecorView().getWidth();
    int sh = getWindow().getDecorView().getHeight();

    // sanity check
    if (sw * sh == 0) {
    Log.e(TAG, "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) {
    mVideoWidth = width;
    mVideoHeight = height;
    mVideoVisibleWidth = visibleWidth;
    mVideoVisibleHeight = visibleHeight;
    mVideoSarNum = sarNum;
    mVideoSarDen = sarDen;
    updateVideoSurfaces();
    }
    }
     

    布局文件:activity_main.xml:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:keepScreenOn="true"
    android:background="@android:color/background_dark"
    tools:context=".NativeActivity">

    <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>
    </FrameLayout>
     

    surface_view.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    </SurfaceView>
    texture_view.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <TextureView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    </TextureView>

    ————————————————
    版权声明:本文为CSDN博主「白皮书CAN」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/u012459903/article/details/88739782

  • 相关阅读:
    输出流OutputStream简单理解
    IO流实现写入规定的acci码值
    事务的ACID属性&&五种状态
    java基础总结之Hashtable
    HBase
    oracle交换分区
    ArrayList 和 LinkedList 的区别(底层数据结构): 什么时候使用arrayList,什么时候使用LinkedList (一个小时)
    Mac中MariaDB数据库的安装步骤
    Mac OS X中MacPorts安装和使用(linux 的 yum)
    SFTP秘钥认证
  • 原文地址:https://www.cnblogs.com/javalinux/p/14544745.html
Copyright © 2011-2022 走看看