Android 使用vlc播放视频

我的需求是播放rtsp视频流,最开始用了Android原生播放器MediaPlayer,但是延迟太大了,感觉要将近10秒,而且不能修改缓冲大小,因为底层写死的(根据Android版本设置了固定的缓冲大小),最终用了开源的vlc

目前项目中使用vlc播放了rtsp视频流,并且有拍照,录制的功能

使用vlc播放,vlc使用的是3.0.0的版本

截图和录制需要在aar中加入Android可调用的方法

需要将aar放到libs文件下,在gradle中配置


libvlcaar


配置aar

然后添加依赖
compile(name:'libvlc-release-3',ext:'aar')

具体代码实现如下

final ArrayList args =new ArrayList<>();//VLC参数

args.add("--rtsp-tcp");//强制rtsp-tcp,加快加载视频速度

args.add("--aout=opensles");

args.add("--audio-time-stretch");

args.add("--sub-source=marq{marquee=\"%Y-%m-%d,%H:%M:%S\",position=10,color=0xFF0000,size=40}");//这行是可以再vlc窗口右下角添加当前时间的

args.add("-vvv");

mLibVLC =new LibVLC(this, args);

mMediaPlayer =new MediaPlayer(mLibVLC);

Rect surfaceFrame =textureView.getHolder().getSurfaceFrame();

//设置vlc视频铺满布局

mMediaPlayer.getVLCVout().setWindowSize(layout_video.getWidth(), layout_video.getHeight());//宽,高  播放窗口的大小

mMediaPlayer.setAspectRatio(layout_video.getWidth()+":"+layout_video.getHeight());//宽,高  画面大小

mMediaPlayer.setScale(0);//这行必须加,为了让视图填满布局

//添加视图

IVLCVout vout =mMediaPlayer.getVLCVout();

vout.setVideoView(textureView);

vout.attachViews();

        Uri uri = Uri.parse(Path.RTSP_URL);//rtsp流地址或其他流地址//"https://media.w3.org/2010/05/sintel/trailer.mp4"

final Media media =new Media(mLibVLC, uri);

int cache =10;

media.addOption(":network-caching=" + cache);

media.addOption(":file-caching=" + cache);

media.addOption(":live-cacheing=" + cache);

media.addOption(":sout-mux-caching=" + cache);

media.addOption(":codec=mediacodec,iomx,all");

mMediaPlayer.setMedia(media);//  

media.setHWDecoderEnabled(false, false);//设置后才可以录制和截屏,这行必须放在mMediaPlayer.setMedia(media)后面,因为setMedia会设置setHWDecoderEnabled为true

mMediaPlayer.play();

这样就可以使用vlc播放rtsp视频了

vlc截图

String path1 = Environment.getExternalStorageDirectory().getAbsolutePath()+"/" +"wy";//路径最后不用/,vlc会自己补充

boolean snapshot =mMediaPlayer.getSnapshot(path1);//这个是vlc  arr里面添加的方法

//通知系統相冊刷新保持的錄屏,拍照后的图片存放在本地相册

Intent intent =new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

intent.setData(Uri.fromFile(new File(path1)));

sendBroadcast(intent);//不添加的话,相册不会更新,手机图库看不到

vlc 录制

boolean onvideo =false;//onvideo是否开始录制false是未录制

String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/" +"wy";

                        if (!onvideo){

Thread myThread =new Thread(new Runnable() {

@Override

                                public void run() {

Log.d("record_video",Thread.currentThread().getName());

                                    if (!isStopThread) {

                                        onvideo =true;

                                        boolean record =mMediaPlayer.record(path);//此方法是vlc  源码添加的,开始录制

                                        Log.d("record1",record+"");

                                    }

}

});

                            myThread.start();

                                tv_recordvideo.setText(R.string.textvideo);

                        }else {

onvideo =false;

                            boolean record =mMediaPlayer.record(null);//结束录制,路径传null

                            Log.d("record2",record+"");

                            tv_recordvideo.setText("");

                            //通知系統相冊刷新保持的錄屏

                                    Intent intent1 =new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

                                    intent1.setData(Uri.fromFile(new File(path)));

                                    sendBroadcast(intent1);

                        }

oppo手机出现不更新画面

E/libEGL: eglCreateWindowSurfaceTmpl:729 error 3003 (EGL_BAD_ALLOC)

 E/VLC: [c637e3b0/4338] libvlc gl: cannot create EGL window surface

 E/VLC: [c5a38530/4338] libvlc window: request 1 not implemented

 E/VLC: [bf07af30/3829] libvlc video output: video output creation failed

 E/VLC: [c645ee30/3829] libvlc decoder: failed to create video output

 E/VLC: [c637e430/4339] libvlc window: request 1 not implemented

 E/BufferQueueProducer: [SurfaceView - com.example.activity.MainActivity#0] connect: already connected (cur=1 req=1)

E/libEGL: eglCreateWindowSurface: native_window_api_connect (win=0xc5a8e808) failed (0xffffffea) (already connected to another API?)

解决方案:

android:hardwareAccelerated="true"//在清单文件中添加了这行,开启了硬件加速,不报上面的错了

然而我用华为手机测试没有这个问题。。。。。

2021.1.25

使用vlc播放器播放smb远程共享文件中的mp4视频

Uri uri = Uri.parse(直接传入smb视频地址);

获取视频长度:

mMediaPlayer.setEventListener,设置监听

IMedia media1 =mMediaPlayer.getMedia();

media1.parseAsync();//这里同步方法拿到的是0,或者-1,我用了异步解决问题

chapter = (int)mMediaPlayer.getLength();

mediaplaye.play();//核心代码,在播放前获取视频长度


mMediaPlayer.setEventListener(new MediaPlayer.EventListener() {

@Override

                public void onEvent(MediaPlayer.Event event) {

//                    Log.d("mMediaPlayer","event.type=="+ event.type);

                    switch (event.type){

case Opening:

Log.d("mMediaPlayer","Opening=="+Opening);

break;

                        case MediaChanged:

Log.d("mMediaPlayer","MediaChanged=="+MediaChanged);

break;

                        case  Buffering:

Log.d("mMediaPlayer","Buffering=="+Buffering);

break;

                        case  Playing:

Log.d("mMediaPlayer","Playing=="+Playing);

break;

                        case  Paused:

Log.d("mMediaPlayer","Paused=="+Paused);

break;

                        case  Stopped:

Log.d("mMediaPlayer","Stopped=="+Stopped);

break;

                        case  EndReached:

//                            textureView.setVisibility(View.INVISIBLE);

//                            network_layout.setVisibility(View.VISIBLE);

//                            tv_network.setText("网络连接断开,请重试");

                            Log.d("mMediaPlayer","EndReached=="+EndReached);

break;

                        case  EncounteredError:

Log.d("mMediaPlayer","EncounteredError=="+EncounteredError);

break;

                        case  TimeChanged:

Log.d("mMediaPlayer","TimeChanged=="+TimeChanged);

break;

                        case  PositionChanged:

if (isPositionChanged){

handler.sendEmptyMessageDelayed(2,0);

                                isPositionChanged =false;

                            }

Log.d("mMediaPlayer","PositionChanged=="+PositionChanged);

break;

                        case  SeekableChanged:

IMedia media1 =mMediaPlayer.getMedia();

                            media1.parseAsync();

                            chapter = (int)mMediaPlayer.getLength();

                            int time =chapter /1000;

                            int miao = time /60;

                            int i1 = time - (miao *60);

                            if (miao<10){

if (i1<10){

String i ="0" + miao +":" +"0" + i1;

                                    pb_seek.setMax(chapter /1000);

                                    tv_pro_right.setText(i);

                                }else if (i1<60){

String i ="0" + miao +":" + i1;

                                    pb_seek.setMax(chapter /1000);

                                    tv_pro_right.setText(i);

                                }

}else if (miao<60){

if (i1<10){

String i = miao +":" +"0" + i1;

                                    pb_seek.setMax(chapter /1000);

                                    tv_pro_right.setText(i);

                                }else if (i1<60){

String i = miao +":" + i1;

                                    pb_seek.setMax(chapter /1000);

                                    tv_pro_right.setText(i);

                                }

}

Log.d("time",time+"");

//                            Message message = new Message();

//                            Bundle bundle = new Bundle();

//                            bundle.putInt("time",chapter);

//

//                            message.setData(bundle);

//                            handler.sendMessageDelayed(message,0);

                            Log.d("chapter", chapter +"==="+  media1.getDuration()+"==="+mMediaPlayer.getChapter()+"==="+mMediaPlayer.getTime()+"==="+mMediaPlayer.getLength()+"==="+mMediaPlayer.getPosition()+"==="+mMediaPlayer.getTitle());

                            Log.d("mMediaPlayer","SeekableChanged=="+SeekableChanged);

break;

                        case  PausableChanged:

Log.d("mMediaPlayer","PausableChanged=="+PausableChanged);

break;

                        case  LengthChanged:

Log.d("mMediaPlayer","LengthChanged=="+LengthChanged);

break;

                        case  Vout:

Log.d("mMediaPlayer","Vout=="+Vout);

break;

                        case  ESAdded:

Log.d("mMediaPlayer","ESAdded=="+ESAdded);

break;

                        case  ESDeleted:

Log.d("mMediaPlayer","ESDeleted=="+ESDeleted);

break;

                        case  ESSelected :

Log.d("mMediaPlayer","ESSelected=="+ESSelected);

break;

                        case  RecordChanged:

Log.d("mMediaPlayer","RecordChanged=="+RecordChanged);

break;

                    }

}

});

            mMediaPlayer.play();

        }catch (Exception e){

}

handler中拿到消息设置进度条

private void setTimer(){

timer =new Timer();

        timerTask =new TimerTask() {

@Override

            public void run() {

if (mMediaPlayer !=null) {

if (mMediaPlayer.isPlaying()) {

runOnUiThread(new Runnable() {

@Override

                            public void run() {

Log.d("totalTime",totalTime+"");

                                pb_seek.setProgress(totalTime);

                                int i =totalTime /60;

                                if (totalTime <=chapter /1000) {

int miao =totalTime - (i *60);

                                    if (i <10) {

if (miao <10) {

tv_pro_left.setText("0"+i+":0" + miao +"");

                                        }else if (miao <60) {

tv_pro_left.setText("0"+i+":" + miao);

                                        }

}else if (i <60) {

if (miao <10) {

tv_pro_left.setText(i+":0" + miao +"");

                                        }else if (miao <60) {

tv_pro_left.setText(i+":" + miao);

                                        }

}

}else {

return;

                                }

totalTime =totalTime +1;

                            }

});

                    }

}

}

};

        timer.schedule(timerTask, 0, 1000);

    }

我的progress布局

<androidx.constraintlayout.widget.ConstraintLayout

    app:layout_constraintHorizontal_chainStyle="spread_inside"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    app:layout_constraintBottom_toBottomOf="parent"

    tools:ignore="MissingConstraints">

        app:layout_constraintHorizontal_weight="1"

        android:layout_marginLeft="@dimen/dp_3"

        android:id="@+id/tv_pro_left"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        app:layout_constraintLeft_toLeftOf="parent"

        android:text="00:00"/>

        style="?android:attr/progressBarStyleHorizontal"

        android:layout_gravity="center_horizontal"

        android:layout_marginTop="10dp"

        app:layout_constraintHorizontal_weight="4"

        android:id="@+id/pb_seek"

        app:layout_constraintRight_toLeftOf="@id/tv_pro_right"

        app:layout_constraintLeft_toRightOf="@id/tv_pro_left"

        android:layout_width="@dimen/dp_300"

        android:layout_height="wrap_content"

        tools:ignore="MissingConstraints" />

        app:layout_constraintHorizontal_weight="1"

        android:layout_marginRight="@dimen/dp_3"

        app:layout_constraintRight_toRightOf="parent"

        android:id="@+id/tv_pro_right"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="00:00"/>

</androidx.constraintlayout.widget.ConstraintLayout>

效果图:

效果图

在activity中关闭资源,避免oom

private void cancelTimer(){

if (timer !=null) {

timer.cancel();

        timer =null;

    }

if (timerTask !=null) {

timerTask.cancel();

        timerTask =null;

    }

}

public void releasePlayer() {

// mMediaPlayer.setVideoCallback(null, null);

    if (mMediaPlayer!=null){

mMediaPlayer.stop();

        mMediaPlayer.setEventListener(null);

    }

if (vout!=null){

vout.detachViews();

  }

if (mLibVLC!=null){

mLibVLC.release();

        mLibVLC =null;

    }

}

目前还有一个问题,就是录制视频的时候要讲当前时间录制进去,我的vlc窗口已经添加了时间,知道的大神可以告知一下。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,607评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,239评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,960评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,750评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,764评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,604评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,347评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,253评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,702评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,893评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,015评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,734评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,352评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,934评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,052评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,216评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,969评论 2 355

推荐阅读更多精彩内容