ijkPlayer.5 播放H264裸流

需求:websocket 接收byte[] h264裸流,传输到c层使用ijkplayer 播放

ffmpeg播放H264裸流
功能已实现,为了方便,读取本地文件做为源数据,此工程亦可播放mp4之类文件
https://github.com/Malone1023/JoyPlayer

int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options);

该函数支持filename/URL,在不大改的情况下,有两种方式可以完成播裸流的工作
1.管道文件
2.AndoidIO协议/新增URLProtocol自定义

AndoidIO之前的文章已经介绍过,本文使用管道文件来完成

注释openVideo()方法如下代码,catch exception同时注释

 String scheme = mUri.getScheme();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mSettings.getUsingMediaDataSource() && (TextUtils.isEmpty(scheme) || scheme.equalsIgnoreCase("file"))) {
                IMediaDataSource dataSource = new FileMediaDataSource(new File(mUri.toString()));
                mMediaPlayer.setDataSource(dataSource);
            }  else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                mMediaPlayer.setDataSource(mAppContext, mUri, mHeaders);
            } else {
                mMediaPlayer.setDataSource(mUri.toString());
            }

新增setDataSourceFd()方法并且在openVideo中调用,使得调用ijk中的 setDataSource(FileDescriptor fd)方法,并调用到
ijkplayer_jni.c中的static void IjkMediaPlayer_setDataSourceFd(JNIEnv *env, jobject thiz, jint fd2)方法

String fileName = "/mnt/sdcard/yy.264";
    FileDescriptor descriptor = null;
    FileOutputStream stream;
    private void setDataSourceFd(){
        try {
            stream = new FileOutputStream(fileName);
            descriptor = stream.getFD();
           //此处只是为了调用到setDataSourceFd  并不需要实际文件
            mMediaPlayer.setDataSource(descriptor);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

2.修改ijkplayer_jni.c/IjkMediaPlayer_setDataSourceFd方法

新增:

    umask(0);
    if(mkfifo(fifoName, 0664) < 0){
        if(errno == EEXIST){
            MPTRACE("file exits\n");
        }else{    
            perror("mkfifo error");
            return -1;
        }
    }
    int fd = open(fifoName, O_RDWR);
    if(fd < 0){
        MPTRACE("open fifo error\n");
        perror("open fifo error");
        return -1;
    }

修改:

retval = ijkmp_set_data_source(mp, fifoName);

3.新增接收方法

int fd;
void ffp_write_data(FFPlayer *ffp,unsigned char * data,int len){
    if(!fd){
        fd = open(fifoName, O_WRONLY);
        if(fd < 0){
            perror("ffp_joy_write_data fifo error");
            return -1;
        }
    }
   write(fd,data,len);
}

这样 ijkPlayer就可以支持播放h264裸流啦。

可能遇到的问题:
1.ffmpeg h264 avformat_open_input err code: -1094995529 网上找的时候说各种情况的,本文遇到的问题是没打开ffmpeg对h264的支持(出现此问题可以先拿ffmpeg直接播该文件,能正常播放的话说明是跟我遇到的一样)
解决办法:
do-compile-ffmpeg.sh文件中新增如下配置,并重新编译ijk的ffmpeg库(执行compile-ffmpeg.sh,同时需要编译ijk的库,替换)

FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-demuxer=h264"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-protocol=udp"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-protocol=264"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-decoder=h264"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-parser=h264"

FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-hwaccel=h264_vaapi"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-hwaccel=h264_dxva2"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-demuxer=mjpeg"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-demuxer=rtsp"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-demuxer=rtp"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-encoder=h264"

2.mkfifo Android Permission denied
在mkfifo的时候可能会出错,原因是需要设置对应的路径要正确
本文使用的路径 /data/data/com.abc/test.fifo(在安卓手机上跑)

3.java byte[] to c unsigned char* buf

static void
IjkMediaPlayer_set_joy_receive_data(JNIEnv* env ,jobject thiz,jbyteArray data, jint jlen)
{
    jbyte* bBuffer = (*env)->GetByteArrayElements(env,data,0);
    unsigned char* buf = (unsigned char*)bBuffer;
    IjkMediaPlayer *mp  = jni_get_media_player(env, thiz);
    ijkmp_set_joy_data(mp,buf,jlen);

}

你可能感兴趣的:(ijkPlayer.5 播放H264裸流)