Android音视频播放库:wlmedia
发布日期:2021-05-20 13:15:45 浏览次数:5 分类:技术文章

本文共 9715 字,大约阅读时间需要 32 分钟。

 

GitHub

功能

**支持:http、https、rtsp、rtp、rtmp、byte[]、加密视频和各种文件格式视频;

**截图、音轨选择、自定义视频滤镜、变速变调、声道切换、无缝切换surface(surfaceview和textureview)、视频比例设置等;

1、Usage

Gradle: 

implementation 'ywl.ywl5320:wlmedia:1.0.6'

2、实例图片

3、调用方式

配置NDK编译平台:

defaultConfig {    ...	ndk {	    abiFilter("arm64-v8a")	    abiFilter("armeabi-v7a")	    abiFilter("x86")	    abiFilter("x86_64")	}	...}

基本权限

4、接入代码

4.1、视频surface选择

// WlSurfaceView 一般播放使用
// WlTextureView 需要做透明、移动、旋转等使用

4.2、创建播放器

4.2.1 播放视频

WlMedia wlMedia = WlMedia.getInstance();//单例模式主要用于视频,音频可以new对象wlMedia.setPlayModel(WlPlayModel.PLAYMODEL_AUDIO_VIDEO);//同时播放音频视频wlSurfaceView.setWlMedia(wlMedia);//给视频surface设置播放器//异步准备完成后开始播放wlMedia.setOnPreparedListener(new WlOnPreparedListener() {        @Override        public void onPrepared() {            wlMedia.start();//开始播放        }    });//surface初始化好了后 开始播放视频(用于一打开activity就播放场景)wlSurfaceView.setOnVideoViewListener(new WlOnVideoViewListener() {        @Override        public void initSuccess() {            wlMedia.setSource("/storage/sdcard1/fcrs.1080p.mp4");//设置数据源            wlMedia.prepared();//异步开始准备播放        }        @Override        public void moveSlide(double value) {        }        @Override        public void movdFinish(double value) {            wlMedia.seek(value);//seek        }    });//自定义滤镜方式String fs = "precision mediump float;" +            "varying vec2 ft_Position;" +            "uniform sampler2D sTexture; " +            "void main() " +            "{ " +            "vec4 v=texture2D(sTexture, ft_Position); " +            "float average = (v.r + v.g + v.b) / 3.0;" +            "gl_FragColor = vec4(average, average, average, v.a);" +            "}";wlMedia.setfShader(fs);wlMedia.changeFilter();

4.2.2 播放音频

WlMedia wlMedia = new WlMedia();wlMedia.setPlayModel(WlPlayModel.PLAYMODEL_ONLY_AUDIO);//设置只播放音频(必须)wlMedia.setSource(WlAssetsUtil.getAssetsFilePath(this, "mydream.m4a"));//设置数据源wlMedia.setOnPreparedListener(new WlOnPreparedListener() {    @Override    public void onPrepared() {        wlMedia.start();    }});wlMedia.prepared();

4.2.3 播放加密视频文件

WlMedia wlMedia = WlMedia.getInstance();//单例模式主要用于视频,音频可以new对象wlMedia.setPlayModel(WlPlayModel.PLAYMODEL_AUDIO_VIDEO);wlSurfaceView.setWlMedia(wlMedia);wlMedia.setBufferSource(true, true);//必须都为truewlMedia.setOnDecryptListener(new WlOnDecryptListener() {    //解密算法    @Override    public byte[] decrypt(byte[] encrypt_data) {        int length = encrypt_data.length;        for(int i = 0; i < length; i++)        {            encrypt_data[i] = (byte) ((int)encrypt_data[i] ^ 666);        }        WlLog.d("decrypt");        return encrypt_data;    }});wlSurfaceView.setOnVideoViewListener(new WlOnVideoViewListener() {        @Override        public void initSuccess() {            wlMedia.setSource(WlAssetsUtil.getAssetsFilePath(WlEncryptActivity.this, "fhcq-ylgzy-dj-encrypt.mkv"));//加密视频源            wlMedia.prepared();        }        @Override        public void moveSlide(double value) {        }        @Override        public void movdFinish(double value) {            wlMedia.seek(value);        }    });

4.2.4 播放byte[]音视频数据

WlMedia wlMedia = WlMedia.getInstance();//单例模式主要用于视频,音频可以new对象wlMedia.setBufferSource(true, false);//必须第一个为true,第二个为falsewlMedia.setPlayModel(WlPlayModel.PLAYMODEL_ONLY_VIDEO);//根据byte类型来设置(可以音频、视频、音视频)wlTextureView.setWlMedia(wlMedia);wlMedia.setOnPreparedListener(new WlOnPreparedListener() {        @Override        public void onPrepared() {            wlMedia.start();        }    });wlTextureView.setOnVideoViewListener(new WlOnVideoViewListener() {    @Override    public void initSuccess() {        new Thread(new Runnable() {            long length = 0;            @Override            public void run() {                try {                    //从文件模拟byte[]数据                    File file = new File(WlAssetsUtil.getAssetsFilePath(WlBufferActivity.this, "mytest.h264"));                    FileInputStream fi = new FileInputStream(file);                    byte[] buffer = new byte[1024 * 64];                    int buffersize = 0;                    int bufferQueueSize = 0;                    exit = false;                    while(true)                    {                        if(exit)                        {                            break;                        }                        if(wlMedia.isPlay())                        {                            WlLog.d("read thread " + bufferQueueSize);                            if(bufferQueueSize < 20)//控制队列大小,不然内存可能会增大溢出                            {                                buffersize = fi.read(buffer);                                if(buffersize <= 0)                                {                                    WlLog.d("read thread ==============================  read buffer exit ...");                                    wlMedia.putBufferSource(null, -1);                                    break;                                }                                bufferQueueSize = wlMedia.putBufferSource(buffer, buffersize);//返回值为底层buffer队列个数                                while(bufferQueueSize < 0)                                {                                    bufferQueueSize = wlMedia.putBufferSource(buffer, buffersize);                                }                            }                            else                            {                                bufferQueueSize = wlMedia.putBufferSource(null, 0);                            }                            sleep(10);                        }                        else                        {                            WlLog.d("buffer exit");                            break;                        }                    }                    wlMedia.stop();                } catch (Exception e) {                    e.printStackTrace();                }            }        }).start();        wlMedia.prepared();    }    @Override    public void moveSlide(double value) {    }    @Override    public void movdFinish(double value) {    }});

5、API

5.1 播放器API

public WlMedia();//构造函数,不依赖上下文public void setSource(String source);//设置数据源(可以是file、url)public void setPlayModel(WlPlayModel playModel);//设置音视频播放模式(可以独立播放音频和视频或者同时播放音视频,默认同时播放音视频)public void setCodecType(WlCodecType codecType);//设置解码器类型(默认优先使用硬解码)public void prepared();异步开始准备播放,成功后会回调WlOnPreparedListener接口public void next();//切歌(数据源设置方法为:setSource)public void start();//开始播放(当异步准备完成后,在WlOnPreparedListener回调里面开始播放)public void pause();//播放暂停public void resume();//暂停后恢复播放public boolean isPlay();//判断是否在播放中public void setMute(WlMute mute);//设置声道(立体声、左声道、右声道)public void setVolume(int percent);//设置声音(0~100)public void setSpeed(float speed);//设置播放速度(0.5f~2f)public void setPitch(float pitch);//设置播放音调(0.5f~2f)public void seek(double secds);//seek 目前是到关键帧(实测精确到时间帧,体验不好,平均等待时间过长,故弃之)public void setSampleRate(WlSampleRate wlSampleRate);//设置音频采样率(用于回调pcm时需要制定采样率情况)public void setShowPcm(boolean showPcm);//设置是否回调pcm音频数据,回调方法:WlOnPcmDataListenerpublic double getNowClock();//获取当前播放时间public double getDuration();//获取时长(如果有在异步准备好后可获取)public void takePicture();//视频截图(是截取surface屏幕图片,自己可根据surface大小和视频宽高对视频图片进行裁剪),回调方法:WlOnTakePictureListenerpublic int putBufferSource(byte[] buffer, int buffer_len);//byte[]方式播放数据入口,返回值为底层队列大小,当buffer_len == 0时,也返回底层队列大小。public void seekNoCallTime();//设置不回调时间,可用于seek过程中UI展示(具体看自己的需求)public void onSurfaceCreate(Surface surface);//设置surface(用于自定义surfaceview)public void onSurfaceChange(int width, int height, Surface surface);//surface大小改变public void onSurfaceDestroy();//surface销毁public void release();//回收surface底层opengl资源public void setTransportModel(WlTransportModel transportModel);//设置播放rtsp的方式(UDP/TCP)public void setClearLastPicture(boolean clearLastPicture);//视频播放完最后一帧是否清屏,true:停留在最后一帧;false:清屏为黑色/** * 设置数据源模式 * 1、bufferSource为true,encryptFileSource为false时,是byte[]模式 * 2、bufferSource为true,encryptFileSource为true时,是file模式,可用于加密视频播放,(回WlOnDecryptListener调里面自己解密) * @param bufferSource byte[]模式 * @param encryptFileSource 是否加密 */public void setBufferSource(boolean bufferSource, boolean encryptFileSource);public void setvShader(String vShader);//设置顶点着色器public void setfShader(String fShader);//设置纹理着色器public void changeFilter();//设置着色器后用于使之生效(切换滤镜)public void scaleVideo(int w, int h);//设置视频宽高比public int getVideoWidth();//获取视频宽public int getVideoHeight();//获取视频高public String[] getAudioChannels();//获取所有音轨,返回音轨名字(默认为Audio)public void setAudioChannel(int index);//设置播放音轨,index为getAudioChannels中得到音轨的索引public void setDelayOffsetTime(double offsetTime);//用于单独播放视频(buffer)时动态调整视频渲染速率,单位秒。

5.2 WlSurfaceView和WlTextureView

SDK自带这2个自定义surfaceview,通过setWlMedia方法与播放器关联,updateMedia方法用于播放中切换显示surface;WlOnVideoViewListener为surface初始化完成回调。开发者可以根据自己情况自定义自己的surfaceview,实现自己的特殊需求。***注:***自定义surface必须调用方法:public void onSurfaceCreate(Surface surface);public void onSurfaceChange(int width, int height, Surface surface);public void onSurfaceDestroy();

5.3 回调函数

public interface WlOnPreparedListener; //异步准备完成回调public interface WlOnTimeInfoListener; //播放时间回调public interface WlOnLoadListener; //加载状态回调public interface WlOnErrorListener; //错误回调public interface WlOnCompleteListener; //播放(资源回收)完成回调public interface WlOnDecryptListener; //解密算法回调public interface WlOnPcmDataListener; //音频PCM数据回调public interface WlOnTakePictureListener; //截图回调public interface WlOnVideoViewListener; //surface 初始化完成回调

6、混淆

-keep class com.ywl5320.wlmedia.* {*;}

7、注意事项

7.1播放器activity配置:

android:configChanges="orientation|keyboardHidden|screenSize"android:launchMode="singleTask"//(建议)

7.2播放器生命周期逻辑

播放器结束有2个回调:error和complete,二者只可能回调其中一个,所以回收回收资源可以在这个2个回调里面进行。如:activity:back->stop->error/complete->release->finish

8、参考资料

Create By:ywl5320 2019-12-16

转载地址:https://blog.csdn.net/ywl5320/article/details/103667160 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android获取(网络和本地)视频缩略图
下一篇:【Python自学】六个易上手的免费Python实战项目,游戏、图片转字符、破解验证码...

发表评论

最新留言

感谢大佬
[***.8.128.20]2024年04月05日 06时47分38秒