android vlc集成以及了解vlc架构

一、近期整理了下之前用过的vlc for android;相关代码下载以及编译可以参考官方WIKI

官方Code下载地址,参考Git

个人Demo地址链接

https://github.com/xiaxiaxa/mgtv_vlc_demo
在这里插入图片描述

二、搭建编译环境,编译vlc生成apk以及相对应的解码库等;

在ubuntu 14.04下面搭建编译环境,安装相关编译工具等;
下载代码:
git clone https://code.videolan.org/videolan/vlc-android.git
在这里插入图片描述在这里插入图片描述

需要配置NDK、JDK等环境变量等:
在这里插入图片描述
ubuntu相关交叉编译工具等可以使用附件sh自动安装

链接: https://pan.baidu.com/s/10s1aoF_SHacT9rEsueJP_A
提取码: aja2

超级用户下,直接运行脚本会安装对应的arm交叉编译工具等;

对应的编译模块以及相关命令:

编译模块命令生成路径
编译apksh compile.sh -a armeabi-v7avlc-android/build/outputs/apk/vanillaARMv7/debug
编译aarsh compile.sh -l -a armeabi-v7a -rlibvlc/build/outputs/aar
编译sosh compile-libvlc.sh -a armeabi-v7alibvlc/private_libs/libs/armeabi-v7a

在这里插入图片描述
aar里面的是libvlc编译出来的相关so库
在这里插入图片描述
个人编译的相关库以及vlc apk上传至网盘

提取码: h5hv

在这里插入图片描述

三、附上个人的Git使用demo,测试rtp/rtsp等直播流是没问题的;(个人主要用vlc来解决直播rtsp等播放问题)

public class VlcPlayActivity extends AppCompatActivity implements 
IVLCVout.OnNewVideoLayoutListener {

private static final boolean ENABLE_SUBTITLES = true;
    private static final String TAG = "VlcActivity";
    public static String SAMPLE_URL = "rtp://239.76.245.115:1234";
    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 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.vlc_play);
        SAMPLE_URL = getIntent().getStringExtra("extra_url");
        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);
        mVideoSurface = (SurfaceView) findViewById(R.id.video_surface);
        if (ENABLE_SUBTITLES) {
            final ViewStub stub = (ViewStub) findViewById(R.id.subtitles_stub);
            mSubtitlesSurface = (SurfaceView) stub.inflate();
            mSubtitlesSurface.setZOrderMediaOverlay(true);
            mSubtitlesSurface.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        releaseData();
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        releaseData();
    }

    private void releaseData() {

        if (isFinishing()) {
            if (mOnLayoutChangeListener != null) {
                if (mVideoSurfaceFrame != null) {
                    mVideoSurfaceFrame.removeOnLayoutChangeListener(mOnLayoutChangeListener);
                }
                mOnLayoutChangeListener = null;
            }
            if (mMediaPlayer != null) {
                mMediaPlayer.getVLCVout().detachViews();
                mMediaPlayer.pause();
                mMediaPlayer.stop();
                mMediaPlayer.release();
                mMediaPlayer = null;
            }

            if (mSubtitlesSurface != null) {
                mSubtitlesSurface = null;
            }

            if (mHandler != null) {
                mHandler.removeCallbacks(null);
            }

        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        final IVLCVout vlcVout = mMediaPlayer.getVLCVout();
        vlcVout.setVideoView(mVideoSurface);
        if (mSubtitlesSurface != null)
            vlcVout.setSubtitlesView(mSubtitlesSurface);
        vlcVout.attachViews(this);

        Media media = new Media(mLibVLC, Uri.parse("rtp://239.76.245.115:1234"));
        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();
        releaseData();
    }

    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;
        }
        if (mMediaPlayer != null) {
            mMediaPlayer.getVLCVout().setWindowSize(sw, sh);
        }
        if (mVideoSurface != null) {
            ViewGroup.LayoutParams lp = mVideoSurface.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;
                mVideoSurface.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 */
                if (mMediaPlayer != null) {
                    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);
            mVideoSurface.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);

            mVideoSurface.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;
        if (isFinishing()){

        } else {
            updateVideoSurfaces();
        }
    }
    }

**demo播放的控制主要是这两个类实现:**

public class PlayerActivity  extends BaseActivity {
    private static final String TAG = "PlayerActivity";
    @ViewInject(R.id.video_play)
    private VideoView mVideoPlay;
    @ViewInject(R.id.progress_loading)
    private ProgressBar mProgresLoading;
    private String mUrl;

    @Override
    public int getLayoutRes() {
        return R.layout.activity_video_player;
    }

    @Override
    public void init() {
        mUrl = getIntent().getStringExtra(ConstData.IntentKey.VIDEO_URL);
        if(TextUtils.isEmpty(mUrl))
            finish();
        mVideoPlay.setOnErrorListener(new MediaPlayer.OnErrorListener() {

            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                Log.i(TAG, "onError");
                mProgresLoading.setVisibility(View.GONE);
                finish();
                return true;
            }
        });
        mVideoPlay.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {

            @Override
            public void onPrepared(MediaPlayer mp) {
                Log.i(TAG, "onPrepared");
                mProgresLoading.setVisibility(View.GONE);
            }
        });
    }



    @Override
    protected void onResume() {
        super.onResume();
        playVideo();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mVideoPlay.pause();

    }

    @Override
    protected void onStop() {
        super.onStop();
        try{
            mVideoPlay.stopPlayback();
        }catch (Exception e){

        }

    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode == KeyEvent.KEYCODE_BACK){
            mProgresLoading.setVisibility(View.GONE);
            finish();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    private void playVideo(){
        try{
            mVideoPlay.stopPlayback();
        }catch (Exception e){

        }
        mProgresLoading.setVisibility(View.VISIBLE);
        mVideoPlay.setVideoURI(Uri.parse(mUrl));
        mVideoPlay.start();
    }

在这里插入图片描述
可以自己把jni部分源码复写,播放主要控制在libvlc

在这里插入图片描述
在这里插入图片描述

四、前期工作做完后,我们可以先来简要了解vlc的播放器工作;音视频的播放我们一般有几个步骤,主要是:

步骤工作内容简要说明
1access访问接收、获取、得到数据资源,包括解析访问源(url), 使用http协议,rtsp协议,ftp协议,建立连接,获取数据
2demux解复杂音频和视频分离,当然也有可能有字幕。通过分析数据包头来判断是什么数据文件,需要用什么解码格式
3decode解码包括音频和视频解码,或者软件解码和硬件解码。
4output输出分为音频和视频的输出(aout和vout)
VLC源码结构对应功能
./config/从命令行和配置文件中加载配置
./control/提供动作控制功能,如播放等操作
./extras/大多是平台的特殊代码
./modules/模块管理
./network/提供网络接口(socket管理,网络接口)
./osd/显示屏幕上的操作
./test/libvlc测试模块
./text/字符集
./interface/提供代码中可以调用的接口,如按键后的硬件作出反应
./playlist/管理播放功能
./input/建立并读取一个输入流,并且分离其中的音频和视频,然后把分离好的音频和视频流发给解码器
./audio_output/初始化音频混合器,即设置正确的同步频率,并对从解码器传来的音频流重新取样
./video_output/初始化视频播放器,把从解码器得到视频画面转化格式从yuv到rgb,然后播放
./stream_output/ /输出音频流和视频流到网络
./misc/libvlc使用的其他部分功能,如线程系统,消息队列等
  • VLC
    采用全模块化结构,通过动态的载入所需的模块,放入一个module_bank的结构体中统一管理,连VLC的Main模块也是通过插件的方式动态载入的(通过module_InitBank函数在初始化建立module_bank时)。对于不支持动态载入插件的系统环境中,VLC也可以采用builtin的方式,在VLC启动的时候静态载入所需要的插件,并放入module_bank统一管理。

五、附上自己编译的源码Vlc生成的apk以及demo生成的apk;

链接: https://pan.baidu.com/s/1YnPus6koPLI4-LEUzPADlA
提取码: w7ya

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
很高兴能够回答您的问题。以下是一个简单的示例代码,可以用于在 Android集成 VLC 播放器: 1. 在您的项目中添加以下依赖项: ``` implementation "de.mrmaffen:vlc-android-sdk:3.2.0@aar" ``` 2. 在您的布局文件中添加一个 SurfaceView: ``` <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 3. 在您的 Activity 中初始化 VLC: ``` import android.net.Uri; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import androidx.appcompat.app.AppCompatActivity; import org.videolan.libvlc.LibVLC; import org.videolan.libvlc.Media; import org.videolan.libvlc.MediaPlayer; import java.util.ArrayList; public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback { private SurfaceView surfaceView; private LibVLC libVLC; private MediaPlayer mediaPlayer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = findViewById(R.id.surfaceView); surfaceView.getHolder().addCallback(this); libVLC = new LibVLC(this); mediaPlayer = new MediaPlayer(libVLC); } @Override public void surfaceCreated(SurfaceHolder holder) { mediaPlayer.getVLCVout().setVideoSurface(holder.getSurface(), holder); mediaPlayer.getVLCVout().attachViews(); Media media = new Media(libVLC, Uri.parse("http://example.com/video.mp4")); mediaPlayer.setMedia(media); mediaPlayer.play(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { mediaPlayer.stop(); mediaPlayer.getVLCVout().detachViews(); } @Override protected void onDestroy() { mediaPlayer.release(); libVLC.release(); super.onDestroy(); } } ``` 请注意,上述示例中的视频 URL 仅用作示例。您应该在 `Uri.parse()` 中使用实际的视频 URL。同时,这只是一个简单的示例,您可能需要对代码进行修改,以满足您的特定需求。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值