ijkPlayer 编译笔记

一、 下载编译

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

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

推荐阅读更多精彩内容