Skip to content

rawVideoData

xinbaicheng edited this page May 27, 2017 · 10 revisions

获取视频原始数据

该方式暂时只在软解的情况下生效

基本设置

视频数据格式

必须在调用 prepareAsync 之前设置

// 输出视频格式为 ABGR8888
ksyMediaPlayer.setOption(KSYMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", KSYMediaPlayer.SDL_FCC_RV32);
// 输出视频格式为 YUV(一般情况是YUV420)
ksyMediaPlayer.setOption(KSYMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", KSYMediaPlayer.SDL_FCC_YV12);
地址对齐

在播放器分配每一帧视频的内存时会对视频的做地址对齐,计算方式如下所示:

/**
 * @param width 视频原始宽度
 * @param align 地址对齐的基值,输出视频格式不同时,此值亦不同
 * @return 地址对齐后的值
 */
public int alignWidth(int width, int align) {
    return (width + align - 1) / align * align;
}
使用示例

开发者需先申请相应的缓存,并交予播放器,播放器方可将视频数据交予开发者。

初始化buffer时,需要根据视频的宽高值计算,视频宽高数据需要在OnPrepared后才是有效数据。

特别提醒

部分MP4视频自带有旋转信息,播放器在渲染时会根据该信息做出旋转,这会影响getVideoWidthgetVideoHeight这两个接口的返回值,在该情况下这两个接口返回的值是 旋转 之后的视频宽高
而原视频视频数据的回调接口onVideoRawDataAvailable中的视频宽高是原始视频宽高

假设开发者在某Activity实现获取视频原始数据的功能,可参考以下代码

private int mVideoWidth, mVideoHeight; // 原始视频宽高
private int widthAfterAligned; // 地址对齐后的宽
private ByteBuffer rawBuffer[] = new ByteBuffer[5]; // 5 is just an example.

private int mVideoOutputFormat; // 视频原始数据的输出格式
private int mVideoBufferSize = 0; // 视频原始数据所需的Buffer大小
private KSYMediaPlayer mKsyMediaPlayer; // 此处只是使用KSYMediaPlayer作为示例,同样可以使用KSYTextureView,接口一致

private IMediaPlayer.OnPreparedListener mOnPreparedListener = new IMediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(IMediaPlayer iMediaPlayer) {
        mVideoWidth = mKsyMediaPlayer.getVideoWidth();
        mVideoHeight = mKsyMediaPlayer.getVideoHeight();
        
        initVideoRawData(); // 初始化输出视频原始数据相关
        mKsyMediaPlayer.start();
    }
};

private KSYMediaPlayer.OnVideoRawDataListener() mVideoRawDataListener = new KSYMediaPlayer.OnVideoRawDataListener(){
    @Override
    public void onVideoRawDataAvailable(IMediaPlayer mp, byte[] buf, int size, int width, int height, int format, long timeStampMS) {
        //You can handle it in another thread, but never forget calling addVideoRawBuffer after it is done

        // 使用含有视频原始数据的 buf
        // ...

        mKsyMediaPlayer.addVideoRawBuffer(buf);		//MUST call it after the buf is handled
}

private void initVideoRawData() {
    // 根据视频原始数据输出格式计算所需的内存大小
    switch (mVideoOutputFormat) {
        case KSYMediaPlayer.SDL_FCC_YV12:
            widthAfterAligned = alignWidth(mVideoWidth, 16);
            mVideoBufferSize = widthAfterAligned * mVideoHeight * 3 / 2;
            break;
        case KSYMediaPlayer.SDL_FCC_RV32:
            widthAfterAligned = alignWidth(mVideoWidth, 4);
            mVideoBufferSize = widthAfterAligned * mVideoHeight * 4;
            break;
    }

    mKsyMediaPlayer.setVideoRawDataListener(mVideoRawDataListener); // 设置监听器

    for(int index=0; index<rawBuffer.length; index++) {
        //注意请在播放初始化之后(比如OnPrepared)再创建buffer
        rawBuffer[index] = ByteBuffer.allocate(mVideoBufferSize); // make sure buffer Not smaller than video resolution
        mKsyMediaPlayer.addVideoRawBuffer(rawBuffer[index].array());
    }
}

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mKsyMediaPlayer = new KSYMediaPlayer.Builder(getApplicationContext()).build();

    mVideoOutputFormat = KSYMediaPlayer.SDL_FCC_RV32// 设置输出的视频原始数据格式为ABGR8888

    mKsyMediaPlayer.setOption(KSYMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", mVideoOutputFormat);
    mKsyMediaPlayer.prepareAsync();
}
Clone this wiki locally