Android集成IjkPlayer

作者: 和平北路 | 来源:发表于2017-04-07 21:24 被阅读7603次

    0x0000 背景

    • 项目需要引入直播功能,而Android原生的VideoView本身是不支持RTMP格式的流媒体播放的。
    • 市面上的开源播放器还是挺好选择的,相比较于IjkPlayer,其他例如Vitamio、VLC的SDK无论使用便利性还是社区的支持都差得远,自己用ffmpeg写成本难以接受。
    • 但是!IjkPlayer在Github上的README文档真心坑,完全按那个文档做连编译都过不了。。

    0x0001 致谢


    0x0002 源码链接

    Github:Bilibili/ijkplayer


    0x0003 编译

    • 安装homebrew、git、yasm
      非核心内容,请自行百度或谷歌
    • 配置Android SDK、NDK环境变量,在.bash_profile增加如下两行
    export ANDROID_SDK=/your/sdk/path
    export ANDROID_NDK=/your/ndk/path
    
    • 下载源码
    git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
    cd ijkplayer-android
    git checkout -B latest k0.7.8.1
    
    • 初始化
    ./init-android.sh
    
    • 编译ffmpeg
    cd android/contrib
    ./compile-ffmpeg.sh clean
    ./compile-ffmpeg.sh all
    
    • 编译IjkPlayer
    cd ..
    ./compile-ijk.sh all
    

    到此为止,完成了对源码的编译,ijkplayer-android的目录结构如图


    工程结构

    0x0004 配置

    • 拷贝gradle文件
      复制/android/ijkplayer/tools文件夹到工程根目录
    • 在工程根目录下的build.gradle文件中增加配置
    ext {
        compileSdkVersion = 25
        buildToolsVersion = "25.0.2"
        targetSdkVersion = 25
        versionCode = 700801
        versionName = "0.7.8.1"
    }
    

    前三条和你的app module的build.gradle保持一致
    后两条和IjkPlayer源码工程中的build.gradle保持一致

    • 依赖关系
      回到刚才我们编译成功的源码目录,如果将/android/ijkplayer作为一个新项目导入Android Studio,运行ijkplayer-example,是可以作为一个独立app run起来的
      我们先把example加入工程:
      File-New-Import Module-/android/ijkplayer/ijkplayer-example
      当然我们希望能把IjkPlayer当做一个第三方库引入,而不是在example工程的基础上实现我们的需求,那么就需要搞清楚各个module的依赖关系:


      各module依赖关系

      说的直白一点,arm64等5个module一看命名大家就明白是基于不同CPU编译产出的so
      为了简化依赖,我们把这几个module的so文件拷贝到example module下,同时删除这几个module,完成后的example目录结构如图


      example目录结构
    • 改造example module
      现在的example module是作为application存在的,如果要作为library引入,要处理以下三点


      调整example build.gradle
      example增加gradle.properties
    • 加入依赖库
      File-Project Structure-app-Dependencies-添加ijkplayer-example


      依赖example module

    0x0005 开发

    IjkVideoView本身继承自FrameLayout,可以和普通的View一样在layout的xml文件中直接加入
    对大多数人来说,平时怎么使用VideoView,现在就怎么使用IjkVideoView即可


    0x0006 问题

    • 如何让播放器填满IjkVideoView展示
      改造SurfaceRenderView的onMeasure方法
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (this.getWidth() != 0) {
            setMeasuredDimension(this.getWidth(), this.getHeight());
            return;
        }
        int width = getDefaultSize(0, widthMeasureSpec);
        int height = getDefaultSize(0, heightMeasureSpec);
        setMeasuredDimension(width, height);
    }
    
    • 启动之后crash
    java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
    

    在AndroidManifest.xml中设置Activity的theme属性

    <activity
        android:name=".MainActivity"
        android:theme="@style/Theme.AppCompat.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    
    • 视频流截图(适用于api14+)
      IjkVideoView改造setRender
    public void setRender(int render) {
        switch (render) {
            case RENDER_NONE:
                setRenderView(null);
                break;
            case RENDER_SURFACE_VIEW:
            case RENDER_TEXTURE_VIEW: {
                TextureRenderView renderView = new TextureRenderView(getContext());
                if (mMediaPlayer != null) {
                    renderView.getSurfaceHolder().bindToMediaPlayer(mMediaPlayer);
                    renderView.setVideoSize(mMediaPlayer.getVideoWidth(), mMediaPlayer.getVideoHeight());
                    renderView.setVideoSampleAspectRatio(mMediaPlayer.getVideoSarNum(), mMediaPlayer.getVideoSarDen());
                    renderView.setAspectRatio(mCurrentAspectRatio);
                }
                setRenderView(renderView);
                break;
            }
            default:
                Log.e(TAG, String.format(Locale.getDefault(), "invalid render %d\n", render));
                break;
        }
    }
    

    增加一个public方法

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
    public Bitmap getShortcut() {
        if (mRenderView instanceof TextureRenderView) {
            return ((TextureRenderView) mRenderView).getBitmap();
        }
        return null;
    }
    

    0x0007 后记

    Android播放器的坑太多,慢慢踩,与君共勉

    相关文章

      网友评论

      本文标题:Android集成IjkPlayer

      本文链接:https://www.haomeiwen.com/subject/xwxkattx.html