ijkplayer 單視頻流直播延遲問題解決過程

一開始我嘗試是通過設(shè)置ijkplayer的參數(shù)去修改延遲锻拘,參數(shù)的修改能把ijkplayer的開播延遲拉到200ms左右绪杏,但是隨著播放時(shí)間增加延遲也在增加下愈,然后帶著問題去網(wǎng)上尋找答案,找到暴走大牙Gongjia兩位大神的解決方案蕾久,但是這種方案僅適用于帶有音頻流的势似,現(xiàn)在適配的流僅有視頻流,用了這兩位的方案后僧著,丟幀是可以履因,但是延遲的問題并沒有解決,因?yàn)闆]有音頻流的視頻的時(shí)間基準(zhǔn)是用視頻流的時(shí)間盹愚,丟完幀后視頻會(huì)卡頓等待視頻的時(shí)間基準(zhǔn)栅迄。后來我在ijkplayer的issue上找了很多關(guān)于卡頓的問題,都沒有找到解決方案皆怕,后面嘗試通過變速的方式去解決這個(gè)問題毅舆,找到了Mr_xkHuang的一篇ijkplayer-音視頻變速播放實(shí)現(xiàn),才了解到了單視頻流的視頻和有音視頻流的視頻關(guān)于時(shí)間基準(zhǔn)的差別愈腾。修改了時(shí)間基準(zhǔn)之后憋活,長(zhǎng)時(shí)直播的延遲問題解決了。
ff_ffplay.c代碼修改如下:

static int read_thread(void *arg)
{
.....
    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
                                   stream_component_open(ffp,st_index[AVMEDIA_TYPE_AUDIO]);
    } else {
    //添加新代碼
        ffp->av_sync_type = AV_SYNC_EXTERNAL_CLOCK;
//注釋掉原有代碼
//        ffp->av_sync_type = AV_SYNC_VIDEO_MASTER;

        is->av_sync_type  = ffp->av_sync_type;
    }
.....

}


經(jīng)過上面的修改虱黄,長(zhǎng)時(shí)放置直播軟解碼延遲穩(wěn)定在400ms左右硬解碼延遲穩(wěn)定在200ms左右悦即,但是出現(xiàn)了一個(gè)更加嚴(yán)重的問題,那就是閃退

代碼會(huì)在renderer_yuv420sp_vtb.m這個(gè)類


static GLboolean yuv420sp_vtb_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)
{
.....
}

這個(gè)方法內(nèi)的隨機(jī)幾行代碼奔潰橱乱,報(bào)的錯(cuò)誤是EXC_BAD_ACCESS辜梳,通過打開僵尸對(duì)象檢測(cè),發(fā)現(xiàn)是

CVPixelBufferRef pixel_buffer

這個(gè)對(duì)象的原因泳叠,然后通過和一個(gè)做c語(yǔ)言的大神溝通后他告訴我要從對(duì)象初始化和查對(duì)象被釋放這兩個(gè)地方入手作瞄。
經(jīng)過一番查找,找到pixel_buffer是通過SDL_VoutOverlay *overlay這個(gè)類拿到的析二,然后我就在ijksdl_vout_overlay_videotoolbox.m這個(gè)類的overlay的初始化方法里面加了

SDL_VoutOverlay *SDL_VoutVideoToolBox_CreateOverlay(int width, int height, SDL_Vout *display)
{
    ...
    //add
    if (opaque->pixel_buffer != NULL) {
        CVBufferRelease(opaque->pixel_buffer);
    }
    opaque->pixel_buffer = NULL;
    return overlay;
}

當(dāng)時(shí)我是用的模擬器測(cè)試的粉洼,結(jié)果很美好,沒有閃退了叶摄,年輕的我以為bug已經(jīng)解決了,但是我想用真機(jī)測(cè)試下延遲問題時(shí)安拟,突然發(fā)現(xiàn)閃退依然存在蛤吓。然后我就繼續(xù)去找還有沒有哪里有使用pixel_buffer這個(gè)結(jié)構(gòu)體的。但是僅有創(chuàng)建pixel_buffer的ijksdl_vout_overlay_videotoolbox.m和使用pixel_buffer的renderer_yuv420sp_vtb.m這兩個(gè)類使用了pixel_buffer糠赦,一時(shí)間大神給的方向找不到路了会傲。
后面我考慮到既然是EXC_BAD_ACCESS锅棕,那么久應(yīng)該是野指針的問題,我就沖這個(gè)方向入手淌山,在使用pixel_buffer的地方對(duì)這個(gè)結(jié)構(gòu)體進(jìn)行retain操作裸燎,增加它的引用計(jì)數(shù)使它不被釋放,結(jié)果是有一點(diǎn)用處泼疑,奔潰的概率降低了德绿,以前1-5分鐘就會(huì)奔潰的代碼現(xiàn)在可以到20-30分鐘奔潰,這讓我以為找到了一條正確的路退渗,結(jié)果確實(shí)我把引用計(jì)數(shù)增加做到了極致移稳,仍然會(huì)有閃退。
這時(shí)候我知道我是找錯(cuò)了方向会油,之后想到pixel_buffer是通過解碼后的frame數(shù)據(jù)轉(zhuǎn)換而來的个粱,有沒有可能是frame被釋放了導(dǎo)致pixel_buffer這個(gè)結(jié)構(gòu)體內(nèi)部的指針形成野指針。帶著這樣的疑問翻翩,我開始打印所有釋放frame的地方都许,結(jié)果真的找到了,每次奔潰的時(shí)候都連著調(diào)用了兩次釋放frame嫂冻。后面我順著這個(gè)釋放的流程胶征,將渲染與釋放的各個(gè)地方按上打印,終于理清楚了ijkplayer渲染的流程絮吵。

通過對(duì)這里流程的理清楚弧烤,我發(fā)現(xiàn)終于找到了為什么會(huì)發(fā)生這樣的問題,既然知道了是由于在渲染之前frame就被釋放了,這樣就好解決問題了蹬敲。
整體是frame在還么有進(jìn)行渲染就進(jìn)行了引用釋放暇昂,釋放后frame在進(jìn)行渲染時(shí)就會(huì)導(dǎo)致上面的情況

我的最終如下:
修改對(duì)ijksdl_vout.h 文件overlay的定義位置添加了一個(gè)屬性:

struct SDL_VoutOverlay {

    //add
    bool nowUseing;//當(dāng)前是否還在使用中
}

然后在ijksdl_vout_overlay_videotoolbox.m這個(gè)類中

//這是overlay的frame數(shù)據(jù)重載方法
static int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame)
{
//add
//    printf("new func_fill_frame :%p\n",overlay);
if (overlay->NowUseing) {//如果當(dāng)前frame正在使用中,就不進(jìn)行數(shù)據(jù)加載
//         printf("nowUsing want  new func_fill_frame:%p\n",overlay);
        return 1;
    }
    overlay->nowUseing = true;//數(shù)據(jù)重載后將overlay的使用狀態(tài)置為true
    ....

}


//overlay的初始化方法
SDL_VoutOverlay *SDL_VoutVideoToolBox_CreateOverlay(int width, int height, SDL_Vout *display)
{
    .....
    //add
    overlay->nowUseing = false;//初始化nowUsing
    //初始化pixel_buffer
    if (opaque->pixel_buffer != NULL) {
        CVBufferRelease(opaque->pixel_buffer);
    }
    opaque->pixel_buffer = NULL;
    
    return overlay;
}

在renderer_yuv420sp_vtb.m這個(gè)類中

//渲染的方法
static GLboolean yuv420sp_vtb_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)
{
    //add
    if (!overlay->nowUseing) {
        return GL_FALSE;
    }

    .....
    //add
//    printf("display over:%p\n",overlay);
    overlay->nowUseing = false;
    return GL_TRUE;
}

在ff_ffplay.c這個(gè)類中

//這是item的引用釋放方法伴嗡,修改為如果該frame還沒有渲染急波,這不釋放引用。
static void frame_queue_unref_item(Frame *vp)
{
//添加這行瘪校,防止剛啟動(dòng)APP或者切換前后臺(tái)bmp為null澄暮,bmp->nowUseing閃退
    if (!vp->bmp) {
       av_frame_unref(vp->frame);
        vp->frame = NULL;
        SDL_VoutUnrefYUVOverlay(vp->bmp);
        avsubtitle_free(&vp->sub);
        return;
    }
    if (vp->bmp->nowUseing) {
        printf("nowUsing wait av_frame_unref:%p\n",vp->bmp);
    }else {
//        printf("SDL_VoutUnrefYUVOverlay(vp->bmp):%p\n",vp->bmp);
        av_frame_unref(vp->frame);
        vp->frame = NULL;
        SDL_VoutUnrefYUVOverlay(vp->bmp);
        avsubtitle_free(&vp->sub);
    }
}

這個(gè)解決辦法并不完美,只是粗暴的處理不讓程序崩潰阱扬,我覺得最好的解決辦法應(yīng)該是找到為什么overlay會(huì)在使用前釋放泣懊。然后讓這種情況不再出現(xiàn)。最近沒有時(shí)間去處理這個(gè)問題麻惶,后面有時(shí)間了再來解決馍刮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市窃蹋,隨后出現(xiàn)的幾起案子卡啰,更是在濱河造成了極大的恐慌静稻,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匈辱,死亡現(xiàn)場(chǎng)離奇詭異振湾,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)亡脸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門押搪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人梗掰,你說我怎么就攤上這事嵌言。” “怎么了及穗?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵峰弹,是天一觀的道長(zhǎng)匀奏。 經(jīng)常有香客問我期吓,道長(zhǎng)呐赡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任焚虱,我火速辦了婚禮购裙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鹃栽。我一直安慰自己躏率,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布民鼓。 她就那樣靜靜地躺著薇芝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪丰嘉。 梳的紋絲不亂的頭發(fā)上夯到,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音饮亏,去河邊找鬼耍贾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛路幸,可吹牛的內(nèi)容都是我干的荐开。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼简肴,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼誓焦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起着帽,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤杂伟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后仍翰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赫粥,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年予借,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了越平。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡灵迫,死狀恐怖秦叛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瀑粥,我是刑警寧澤挣跋,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站狞换,受9級(jí)特大地震影響避咆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜修噪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一查库、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧黄琼,春花似錦樊销、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至弛矛,卻和暖如春够吩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背丈氓。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工周循, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人万俗。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓湾笛,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親闰歪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嚎研,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348