android vlc集成以及了解vlc架构

   日期:2020-07-13     浏览:98    评论:0    
核心提示:一、近期整理了下之前用过的vlc for android;相关代码下载以及编译可以参考官方wiki下载地址,参考GitVLC源码结构对应功能./config/从命令行和配置文件中加载配置./control/提供动作控制功能,如播放等操作./extras/大多是平台的特殊代码./modules/模块管理./network/提供网络接口(socket管理,网络接口)./osd/显示屏幕上的操作./test/libvlc测试模块./_android 集成vlcvlc

一、近期整理了下之前用过的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交叉编译工具等;

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

编译模块 命令 生成路径
编译apk sh compile.sh -a armeabi-v7a vlc-android/build/outputs/apk/vanillaARMv7/debug
编译aar sh compile.sh -l -a armeabi-v7a -r libvlc/build/outputs/aar
编译so sh compile-libvlc.sh -a armeabi-v7a libvlc/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) {
        
        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; 
                    else
                        scale = displayH / (float) videoH; 
                    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) {
                
                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) {
                
                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) {
                
                vw = mVideoVisibleWidth;
                ar = (double) mVideoVisibleWidth / (double) mVideoVisibleHeight;
            } else {
                
                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; 
                    else
                        dw = dh * ar; 
                    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的播放器工作;音视频的播放我们一般有几个步骤,主要是:

步骤 工作内容 简要说明
1 access访问 接收、获取、得到数据资源,包括解析访问源(url), 使用http协议,rtsp协议,ftp协议,建立连接,获取数据
2 demux解复杂 音频和视频分离,当然也有可能有字幕。通过分析数据包头来判断是什么数据文件,需要用什么解码格式
3 decode解码 包括音频和视频解码,或者软件解码和硬件解码。
4 output输出 分为音频和视频的输出(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

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服