美文网首页Android 多媒体
ijkPlayer 编译笔记

ijkPlayer 编译笔记

作者: chjxidian | 来源:发表于2018-12-31 20:01 被阅读0次

一、 下载编译

gitclonehttps://github.com/Bilibili/ijkplayer.git ijkplayer-android

cd ijkplayer-android

git checkout -B latest k0.8.8

二、初始化系统配置

./init-android.sh

cd config/

ls   # 查看文件清单

module-default.sh module-lite-hevc.sh module-lite.shmodule.sh

先删除modelu.sh  rm -r module.sh

修改module-lite.sh 中配置项 vim module-lite.sh中添加如下配置

export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp"

export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=sdp"

export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtp"

export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp"

export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=tcp"

保存退出。执行以下命令

rm module.sh

ln -s module-lite.sh module.sh  #创建软连接

三、开始修改相关源码

该命令有可能会出现module.sh中遗漏,因此对比下module-lite.sh是否与module.sh一致

降低延时编译,修改ff_ffplay.c文件 进入目录cd ijkmedia/ijkplayer/ 修改ff_ffplay.c文件

修改其中packet_queue_get_or_buffering方法 如下:

static int packet_queue_get_or_buffering(FFPlayer *ffp, PacketQueue *q, AVPacket *pkt, int *serial, int finished)

{

    while (1) {

                        int new_packet = packet_queue_get(q, pkt, 1, serial);

                        if (new_packet < 0){

                                new_packet = packet_queue_get(q, pkt, 0, serial);

                                if(new_packet < 0)

                                        return -1;

                        } else if (new_packet == 0) {

                                if (!finished)

                                        ffp_toggle_buffering(ffp, 1);

                                        new_packet = packet_queue_get(q, pkt, 1, serial);

                                if (new_packet < 0)

                                    return -1;

    }

    if (finished == *serial) {

            av_free_packet(pkt);

            continue;

        } else {

        break;

        }    

    }

    return 1;

}

修改此处方法编译测试发现视频播放还是存在一秒左右的延时,达不到预计效果,则继续修改vp_duration方法 ,如下:

static double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) {

  /* if (vp->serial == nextvp->serial) {

        double duration = nextvp->pts - vp->pts;

        if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration)

            return vp->duration;

        else

            return duration;

    } else {

        return 0.0;

    }*/

    return vp->duration;

}

直接return;修改ffplay_video_thread方法:

static int ffplay_video_thread(void *arg)

{

    FFPlayer *ffp = arg;

    VideoState *is = ffp->is;

    AVFrame *frame = av_frame_alloc();

    double pts;

    double duration;

    int ret;

    AVRational tb = is->video_st->time_base;

    //AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);

    int64_t dst_pts = -1;

    int64_t last_dst_pts = -1;

    int retry_convert_image = 0;

    int convert_frame_count = 0;

#if CONFIG_AVFILTER

    AVFilterGraph *graph = avfilter_graph_alloc();

    AVFilterContext *filt_out = NULL, *filt_in = NULL;

    int last_w = 0;

    int last_h = 0;

    enum AVPixelFormat last_format = -2;

    int last_serial = -1;

    int last_vfilter_idx = 0;

    if (!graph) {

        av_frame_free(&frame);

        return AVERROR(ENOMEM);

    }

#else

    ffp_notify_msg2(ffp, FFP_MSG_VIDEO_ROTATION_CHANGED, ffp_get_video_rotate_degrees(ffp));

#endif

    if (!frame) {

#if CONFIG_AVFILTER

        avfilter_graph_free(&graph);

#endif

        return AVERROR(ENOMEM);

    }

    for (;;) {

        ret = get_video_frame(ffp, frame);

        if (ret < 0)

            goto the_end;

        if (!ret)

            continue;

        if (ffp->get_frame_mode) {

            if (!ffp->get_img_info || ffp->get_img_info->count <= 0) {

                av_frame_unref(frame);

                continue;

            }

            last_dst_pts = dst_pts;

            if (dst_pts < 0) {

                dst_pts = ffp->get_img_info->start_time;

            } else {

                dst_pts += (ffp->get_img_info->end_time - ffp->get_img_info->start_time) / (ffp->get_img_info->num - 1);

            }

            pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);

            pts = pts * 1000;

            if (pts >= dst_pts) {

                while (retry_convert_image <= MAX_RETRY_CONVERT_IMAGE) {

                    ret = convert_image(ffp, frame, (int64_t)pts, frame->width, frame->height);

                    if (!ret) {

                        convert_frame_count++;

                        break;

                    }

                    retry_convert_image++;

                    av_log(NULL, AV_LOG_ERROR, "convert image error retry_convert_image = %d\n", retry_convert_image);

                }

                retry_convert_image = 0;

                if (ret || ffp->get_img_info->count <= 0) {

                    if (ret) {

                        av_log(NULL, AV_LOG_ERROR, "convert image abort ret = %d\n", ret);

                        ffp_notify_msg3(ffp, FFP_MSG_GET_IMG_STATE, 0, ret);

                    } else {

                        av_log(NULL, AV_LOG_INFO, "convert image complete convert_frame_count = %d\n", convert_frame_count);

                    }

                    goto the_end;

                }

            } else {

                dst_pts = last_dst_pts;

            }

            av_frame_unref(frame);

            continue;

        }

#if CONFIG_AVFILTER

        if (  last_w != frame->width

            || last_h != frame->height

            || last_format != frame->format

            || last_serial != is->viddec.pkt_serial

            || ffp->vf_changed

            || last_vfilter_idx != is->vfilter_idx) {

            SDL_LockMutex(ffp->vf_mutex);

            ffp->vf_changed = 0;

            av_log(NULL, AV_LOG_DEBUG,

                  "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n",

                  last_w, last_h,

                  (const char *)av_x_if_null(av_get_pix_fmt_name(last_format), "none"), last_serial,

                  frame->width, frame->height,

                  (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), is->viddec.pkt_serial);

            avfilter_graph_free(&graph);

            graph = avfilter_graph_alloc();

            if ((ret = configure_video_filters(ffp, graph, is, ffp->vfilters_list ? ffp->vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) {

                // FIXME: post error

                SDL_UnlockMutex(ffp->vf_mutex);

                goto the_end;

            }

            filt_in  = is->in_video_filter;

            filt_out = is->out_video_filter;

            last_w = frame->width;

            last_h = frame->height;

            last_format = frame->format;

            last_serial = is->viddec.pkt_serial;

            last_vfilter_idx = is->vfilter_idx;

            //frame_rate = av_buffersink_get_frame_rate(filt_out);

            SDL_UnlockMutex(ffp->vf_mutex);

        }

        ret = av_buffersrc_add_frame(filt_in, frame);

        if (ret < 0)

            goto the_end;

        while (ret >= 0) {

            is->frame_last_returned_time = av_gettime_relative() / 1000000.0;

            ret = av_buffersink_get_frame_flags(filt_out, frame, 0);

            if (ret < 0) {

                if (ret == AVERROR_EOF)

                    is->viddec.finished = is->viddec.pkt_serial;

                ret = 0;

                break;

            }

            is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time;

            if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)

                is->frame_last_filter_delay = 0;

            tb = av_buffersink_get_time_base(filt_out);

#endif

            //duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0);

duration = 0.01;

            pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);

            ret = queue_picture(ffp, frame, pts, duration, frame->pkt_pos, is->viddec.pkt_serial);

            av_frame_unref(frame);

#if CONFIG_AVFILTER

        }

#endif

        if (ret < 0)

            goto the_end;

    }

the_end:

#if CONFIG_AVFILTER

    avfilter_graph_free(&graph);

#endif

    av_log(NULL, AV_LOG_INFO, "convert image convert_frame_count = %d\n", convert_frame_count);

    av_frame_free(&frame);

    return 0;

}

该方法是直接修改duration 等于0.01即可。修改完善

编译测试播放视频延时在500ms左右,预计效果

四、编译

 cd ..

 cd android/contrib/

 ./compile-ffmpeg.sh clean

 ./compile-ffmpeg.sh all

等待编译,编译需要一定时间,相关联库只要安装完善,编译应是正常,若出现库确实,重新安装再次编译即可

编译完成之后,编译Android 库

 cd ..

 ./compile-ijk.sh all   # all编译所有平台的库

五、使用

在jniLibs中加入编译平台的so

初始化属性:

        IjkMediaPlayer.loadLibrariesOnce(null);

        IjkMediaPlayer.native_profileBegin("libijkplayer.so");

        ijkMediaPlayer = new IjkMediaPlayer();

        ijkMediaPlayer.setLogEnabled(false);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzemaxduration", 100L);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", 10240L);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "flush_packets", 1L);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0L);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1L);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "rtsp_transport", "tcp");

        //ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 60);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-fps", 0);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "fps", 30);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_YV12);

        //ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "fflags", "nobuffer");

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "max-buffer-size", 1024);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", 10);

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 1);

//     ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probsize", "4096");

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzeduration", "2000000");

        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT,"http-detect-range-support",0);

至此整个编译完成。

参考文献

https://blog.csdn.net/qq_19317197/article/details/83084631

相关文章

网友评论

    本文标题:ijkPlayer 编译笔记

    本文链接:https://www.haomeiwen.com/subject/bspwlqtx.html