JavaCV + FFmpeg 拉流播放器

一、设计方案

一个简单的拉流播放器,需要具备以下功能:

  1. 将直播流拉取到设备上并展现出来
  2. 保证播放当前直播流的音视频是同步的
  3. 播放视频时可以切换全屏幕与非全屏

二、定义播放器的生命周期

在定义播放器的生命周期们需要做到以下两步:

1. 先定义一下播放器的事件   

2. 定义播放器展示的控件

1. 定义播放器事件

一个播放器,需要定义出来相应的播放器的事件,最基本的播放器的操作就是:播放、暂停、停止。示例代码如下:

/**
 * 播放器抽象类
 */
public abstract class Player {

    protected boolean play = false;

    public void play() {
        this.play = true;
    }

    public void pause() {
        this.play = false;
    }

    public void stop() {
        this.play = false;
    }
}

2. 定义SurfaceView来显示拉取的视频流

这里其实和原生的MediaPlayer及Ijkplayer是一样的,都是监听Surface的状态来控制播放器:创建,暂停,停止并release。

这里我们使用的控件是SurfaceView,创建一个VideoSurfaceView继承SurfaceView,并实现SurfaceHolder.Callback接口:

@Override
public void surfaceCreated(SurfaceHolder holder) {
    initLayout(mPlayer.getWidth(), mPlayer.getHeight());
    play();
    if (onPreparedListener != null) onPreparedListener.onPrepared();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    Log.v(TAG, "surfaceChanged...");
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    mPlayer.pause();
}

public void releasePlayer() {
    mPlayer.stop();
}

到这里我们把基本的播放器的生命周期的控制部分完成了,接下来就是完成基本的音视频数据的获取和播放了。

三、使用JavaCV + FFmpeg的API播放拉取音视频流

我们使用的是 JavaCV + FFmpeg的API,关于JavaCV的基本的介绍在上一篇文章 JavaCV入门 里面已经做了,下面一边介绍使用到的核心类一边说明音视频播放的流程:

1. FFmpegFrameGrabber

所在package包为:org.bytedeco.javacv,完整类名为:org.bytedeco.javacv.FFmpegFrameGrabber

FFmpegFrameGrabber可以理解为解码器,也可以理解为帧收集器,主要作用就是将视频流以帧的形式拉去到手机设备上。

mFrameGrabber = FFmpegFrameGrabber.createDefault(path);

上面的代码就是创建FFmpegFrameGrabber的方式,path就是要拉取流的地址。

mFrameGrabber.setPixelFormat(AV_PIX_FMT_RGBA);

设置帧收集时的像素格式,这块设置AV_PIX_FMT_RGBA的原因主要是,我们展示画面的时候是转换为Bitmap格式的。

mFrameGrabber.setOption("fflags", "nobuffer");

上面的代码表示我们可以像ijkplayer一样,设置一些参数,这些参数格式我们可以参考ijkplayer也可以去ffmpeg命令行的一些设置参数文档里面去查找,这里就不多赘述了。

mFrameGrabber.start();

上面的代码就是让帧收集器启动,这样就开始拉流了。

2. Frame

所在package包为:org.bytedeco.javacv,完整类名为:org.bytedeco.javacv.Frame

Frame 是一个用于管理音频和视频帧数据的类。 在CanvasFrame、FrameGrabber、FrameRecorder及他们的子类里面都有用到。

Frame grabframe = mFrameGrabber.grab(); 

上面的代码表示从帧收集器里面抓去最新的帧:

播放音频:grabframe.samples里面获取到的就是原始的pcm音频数据,交给AudioTrack处理就ok了。

播放视频:首先需要将Frame图像转换为Bitmap,AndroidFrameConverter.convert(frame)就可以转换,但是在这之前需要使用OpenCVFrameConverter.ToIplImage将抓出来的Frame转换一下。

Canvas canvas = mHolder.lockCanvas();
canvas.drawBitmap(bmp, null, new Rect(0, 0, canvas.getWidth(), frame.imageHeight * canvas.getWidth() / frame.imageWidth), null);
mHolder.unlockCanvasAndPost(canvas);

上面的代码表示将获取到的位图绘制到SurfaceHolder里面去,这里建议启动线程去绘制,这样效率会高很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值