轉(zhuǎn)載請注明出處:http://www.reibang.com/p/b287fa51bd50
本文出自 容華謝后的博客
0.寫在前面
使用IjkPlayer內(nèi)核播放RTMP視頻流的時候,在網(wǎng)絡(luò)不好的情況下空免,延遲會越來越高紫皇,因為項目對視頻實時性有一定的要求慰安,最近一直在解決這個問題,看了下源碼中的Issues聪铺,發(fā)現(xiàn)很多人也遇到了這個問題化焕,一通參數(shù)設(shè)置下去效果有點改善但不多,也試過編譯別人已經(jīng)改好的版本铃剔,發(fā)現(xiàn)效果也不太理想撒桨,無它脂倦,只能自己動手改改了。
先說下為什么會發(fā)生延遲的現(xiàn)象元莫,本文只討論拉流端的優(yōu)化赖阻,當(dāng)然實際項目應(yīng)用的時候,推流端也要一起優(yōu)化下踱蠢。當(dāng)網(wǎng)絡(luò)波動的時候火欧,拉流端讀取不到數(shù)據(jù),等網(wǎng)絡(luò)恢復(fù)正常茎截,會把之前的數(shù)據(jù)讀取回來苇侵,這時緩存就會變大,但拉流端又無法一下子消耗這么多緩存企锌,就會一直有延遲榆浓。
網(wǎng)上有兩種解決方案,一種是當(dāng)檢測到緩存隊列中視頻時長大于設(shè)定的區(qū)間時撕攒,進(jìn)行視頻倍速播放陡鹃,快速消耗緩存隊列中的視頻幀,優(yōu)點是可以避免卡頓抖坪,實際試了下萍鲸,缺點也很明顯,就是視頻追幀一直追不上擦俐。另一種也是檢測緩存隊列脊阴,當(dāng)達(dá)到上限時,進(jìn)行視頻丟幀處理蚯瞧,試了下發(fā)現(xiàn)效果還可以嘿期,在此記錄下,分享給各位同學(xué)埋合。
1.GOP說明
GOP 全稱是 Group of Pictures备徐,顧名思義就是連續(xù)的一組圖像,視頻流可以理解成是由一張張的圖片構(gòu)成的饥悴,但是這樣會造成視頻的體積過大坦喘,那怎么樣來減少體積呢盲再,人們想到西设,連續(xù)的圖片中會有很多重復(fù)的場景,每次都傳輸也太沒有效率了答朋,可不可以改成贷揽,傳一張圖片,然后后面只傳這張圖片變化的部分呢梦碗,于是便有了GOP的概念禽绪。
GOP是由 I-幀蓖救、P-幀、B-幀 組成的一個連續(xù)幀序列印屁,一個視頻又由多個GOP組成循捺。
I-幀:就是我們常說的關(guān)鍵幀,是一張完整的圖片雄人,一個GOP中只有一個I-幀从橘。
P-幀:預(yù)測編碼圖像幀,它需要之前的I-幀或P-幀作為參考幀進(jìn)行編碼础钠。P-幀會分析出參考幀中總是不變的部分恰力,只有變化的部分會被編碼,一個GOP中有多個P-幀旗吁。
B-幀:雙向預(yù)測編碼圖像幀踩萎,它需要同時使用之前的I-幀或P-幀和之后的I-幀或P-幀進(jìn)行編碼,記錄的是前后參考幀之間的差別很钓,一個GOP中有多個B-幀香府。
2.DTS & PTS
上面講到,由于B-幀是雙向預(yù)測的码倦,需要未來的參考幀才能解碼回还,所以就需要一些輔助解碼的工具。
DTS:Decode Timestamp叹洲,解碼時間戳柠硕。
PTS:Presentation Timestamp,顯示時間戳运提。
編碼器在編碼時需要提供DTS和PTS蝗柔,而解碼器在解碼時會根據(jù)DTS順序解碼,再根據(jù)PTS順序播放民泵。
可以看到癣丧,PTS順序是圖中的1-9順序,對應(yīng)的DTS順序如下栈妆,在解碼B-幀之前胁编,要先解碼P-參考幀。
3.源碼修改
源碼位置:/ijkmedia/ijkplayer/ff_ffplay.c
3.1 修改read_thread方法
在外部設(shè)置一個可配置的緩沖區(qū)參數(shù)max_cached_duration鳞尔,用于設(shè)置緩沖區(qū)內(nèi)視頻長度的上限嬉橙,當(dāng)設(shè)置這個參數(shù)之后,即開啟追幀功能寥假。
在read_thread方法方法中市框,有一個for循環(huán)用于處理視頻幀數(shù)據(jù),在這里進(jìn)行緩存區(qū)檢測功能糕韧,我加了一個cache_check_period配置枫振,如果不想檢測太快的話喻圃,可以配置和這個參數(shù),單位都是毫秒粪滤。
static int read_thread(void *arg)
{
...
// 如果設(shè)置了緩沖區(qū)時間斧拍,realtime參數(shù)設(shè)置為0
if (is->max_cached_duration > 0) {
is->realtime = 0;
}else{
is->realtime = is_realtime(ic);
}
...
// 上一次的檢測時間
int64_t last_control_queue_time = 0;
for (;;) {
...
// 獲取當(dāng)前時間
struct timeval time_now;
gettimeofday(&time_now, NULL);
int64_t current_time = (int64_t)time_now.tv_sec * 1000 + time_now.tv_usec / 1000;
// 計算時間差
int64_t time_diff = current_time - last_control_queue_time;
av_log(ffp, AV_LOG_INFO, "control_queue_duration time_diff = %" PRId64, time_diff);
// 緩存區(qū)檢測
if (is->max_cached_duration > 0 && time_diff > is->cache_check_period) {
control_queue_duration(ffp, is);
last_control_queue_time = current_time;
}
if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
packet_queue_put(&is->audioq, pkt);
} else if (pkt->stream_index == is->video_stream && pkt_in_play_range
&& !(is->video_st && (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC))) {
packet_queue_put(&is->videoq, pkt);
} else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
packet_queue_put(&is->subtitleq, pkt);
} else {
av_packet_unref(pkt);
}
}
}
3.2 control_queue_duration方法定義
當(dāng)緩存時長大于設(shè)定的上限時,就會執(zhí)行丟幀操作杖小,其中視頻和音頻的丟幀操作類似饮焦,實際測試的時候,如果頻繁丟幀窍侧,畫面會很卡頓县踢,所以加了一個丟幀的間隔配置cache_delete_period,用于限制丟幀的最小間隔伟件。當(dāng)緩存區(qū)滿了硼啤,但是還沒有到丟幀間隔,也不會進(jìn)行丟幀斧账,防止網(wǎng)慢的時候一直在丟幀谴返。
// 上一次丟幀的時間
int64_t last_drop_time = 0;
static void control_queue_duration(FFPlayer *ffp, VideoState *is) {
if (is->max_cached_duration <= 0) {
return;
}
// 音頻流
if (is->audio_st) {
return control_audio_queue_duration(ffp, is);
}
// 視頻流
if (is->video_st) {
return control_video_queue_duration(ffp, is);
}
}
static void control_video_queue_duration(FFPlayer *ffp, VideoState *is) {
// 判斷時間基是否有效
int time_base_valid = is->video_st->time_base.den > 0 && is->video_st->time_base.num > 0;
if (!time_base_valid) {
return;
}
// 加鎖
SDL_LockMutex(is->videoq.mutex);
// 包數(shù)量
int nb_packets = is->videoq.nb_packets;
// 緩存時長
int64_t cached_duration = -1;
// 總時長
int64_t duration = 0;
if (is->videoq.first_pkt && is->videoq.last_pkt) {
// 計算隊列中的總時長
duration = is->videoq.last_pkt->pkt.pts - is->videoq.first_pkt->pkt.pts;
// 計算緩存時長
cached_duration = duration * av_q2d(is->video_st->time_base) * 1000;
}
// 解鎖
SDL_UnlockMutex(is->videoq.mutex);
// 獲取當(dāng)前時間,毫秒
struct timeval time_now;
gettimeofday(&time_now, NULL);
int64_t current_time = (int64_t)time_now.tv_sec * 1000 + time_now.tv_usec / 1000;
// 計算時間差
int64_t time_diff = current_time - last_drop_time;
av_log(NULL, AV_LOG_INFO, "video cached_duration = %lld, nb_packets = %d, time_diff = %" PRId64,
cached_duration, nb_packets, time_diff);
// 如果大于設(shè)定的緩存時長 && 在設(shè)置的丟幀時間間隔內(nèi)
if (cached_duration > is->max_cached_duration && time_diff > is->cache_delete_period) {
// 丟棄隊列中的一半視頻幀數(shù)據(jù)
int64_t drop_to_pts = is->videoq.last_pkt->pkt.pts - (duration / 2);
drop_queue_until_pts(&is->videoq, drop_to_pts);
last_drop_time = current_time;
}
}
static void control_audio_queue_duration(FFPlayer *ffp, VideoState *is) {
int time_base_valid = is->audio_st->time_base.den > 0 && is->audio_st->time_base.num > 0;
if (!time_base_valid) {
return;
}
// 加鎖
SDL_LockMutex(is->audioq.mutex);
// 包數(shù)量
int nb_packets = is->audioq.nb_packets;
// 緩存時長
int64_t cached_duration = -1;
// 總時長
int64_t duration = 0;
if (is->audioq.first_pkt && is->audioq.last_pkt) {
// 計算隊列中的總時長
duration = is->audioq.last_pkt->pkt.pts - is->audioq.first_pkt->pkt.pts;
// 計算緩存時長
cached_duration = duration * av_q2d(is->audio_st->time_base) * 1000;
}
// 解鎖
SDL_UnlockMutex(is->audioq.mutex);
// 獲取當(dāng)前時間
struct timeval time_now;
gettimeofday(&time_now, NULL);
int64_t current_time = (int64_t)time_now.tv_sec * 1000 + time_now.tv_usec / 1000;
// 計算時間差
int64_t time_diff = current_time - last_drop_time;
av_log(NULL, AV_LOG_INFO, "audio cached_duration = %lld, nb_packets = %d, time_diff = %" PRId64,
cached_duration, nb_packets, time_diff);
// 如果大于設(shè)定的緩存時長 && 在設(shè)置的丟幀時間間隔內(nèi)
if (cached_duration > is->max_cached_duration && time_diff > is->cache_delete_period) {
// 丟棄隊列中的一半音頻幀數(shù)據(jù)
int64_t drop_to_pts = is->audioq.last_pkt->pkt.pts - (duration / 2);
drop_queue_until_pts(&is->audioq, drop_to_pts);
last_drop_time = current_time;
}
}
3.3 drop_queue_until_pts方法定義
如果緩存丟幀滿足條件咧织,則會調(diào)用下面的方法進(jìn)行丟幀操作嗓袱,每次丟幀都是丟完整的GOP組,否則會造成花屏习绢。
static void drop_queue_until_pts(PacketQueue *q, int64_t drop_to_pts) {
MyAVPacketList *pkt1 = NULL;
// 記錄刪除的包數(shù)量
int del_nb_packets = 0;
while (pkt1 = q->first_pkt) {
// 如果是關(guān)鍵幀且時間戳大于等于目標(biāo)時間戳渠抹,跳出循環(huán)
if ((pkt1->pkt.flags & AV_PKT_FLAG_KEY) && pkt1->pkt.pts >= drop_to_pts) {
break;
}
q->first_pkt = pkt1->next;
if (!q->first_pkt)
q->last_pkt = NULL;
q->nb_packets--;
++del_nb_packets;
// 更新隊列的大小
q->size -= pkt1->pkt.size + sizeof(*pkt1);
// 更新隊列的總時長
if (pkt1->pkt.duration > 0)
q->duration -= pkt1->pkt.duration;
av_free_packet(&pkt1->pkt);
#ifdef FFP_MERGE
av_free(pkt1);
#else
pkt1->next = q->recycle_pkt;
q->recycle_pkt = pkt1;
#endif
}
av_log(NULL, AV_LOG_INFO, "del_nb_packets = %d", del_nb_packets);
}
3.4 外部配置
源碼位置:/ijkmedia/ijkplayer/ff_ffplay_def.h
在VideoState中定義三個參數(shù),分別是最大緩存時長闪萄,緩存檢測間隔梧却,緩存刪除間隔。
typedef struct VideoState {
...
int max_cached_duration;
int cache_check_period;
int cache_delete_period;
} VideoState;
在read_thread方法中獲取下獲取下:
// 獲取最大緩存時長配置
AVDictionaryEntry *max_cached_duration_entry = av_dict_get(ffp->player_opts, "max_cached_duration", NULL, 0);
if (max_cached_duration_entry) {
int max_cached_duration = atoi(max_cached_duration_entry->value);
if (max_cached_duration <= 0) {
is->max_cached_duration = 0;
} else {
is->max_cached_duration = max_cached_duration;
}
} else {
is->max_cached_duration = 0;
}
// 獲取緩存檢測間隔配置
AVDictionaryEntry *cache_check_period_entry = av_dict_get(ffp->player_opts, "cache_check_period", NULL, 0);
if (cache_check_period_entry) {
int cache_check_period = atoi(cache_check_period_entry->value);
if (cache_check_period <= 0) {
is->cache_check_period = 0;
} else {
is->cache_check_period = cache_check_period;
}
} else {
is->cache_check_period = 0;
}
// 獲取緩存刪除間隔配置
AVDictionaryEntry *cache_delete_period_entry = av_dict_get(ffp->player_opts, "cache_delete_period", NULL, 0);
if (cache_delete_period_entry) {
int cache_delete_period = atoi(cache_delete_period_entry->value);
if (cache_delete_period <= 0) {
is->cache_delete_period = 0;
} else {
is->cache_delete_period = cache_delete_period;
}
} else {
is->cache_delete_period = 0;
}
av_log(NULL, AV_LOG_INFO, "config: max_cached_duration = %d, cache_check_period = %d, cache_delete_period = %d",
is->max_cached_duration, is->cache_check_period, is->cache_delete_period);
4.參數(shù)配置
4.1 IjkPlayer參數(shù)
// 是否啟用無限緩沖區(qū)
// 1.啟用無限緩沖區(qū)败去,防止播放過程中出現(xiàn)緩沖中斷 0.禁用無限緩沖區(qū)
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "infbuf", 1);
// 設(shè)置播放前的探測時間放航,指定探測多長時間的視頻數(shù)據(jù)以確定流信息(單位:微秒)
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzeduration", 50000);
// 設(shè)置播放前的最大探測時間,指定最大探測時間圆裕,以防止探測時間過長(單位:微秒)
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzemaxduration", 50000);
// 每處理一個packet之后刷新io上下文
// 1.每處理一個數(shù)據(jù)包后刷新I/O上下文广鳍,以確保數(shù)據(jù)的連續(xù)性
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "flush_packets", 1);
// 設(shè)置播放器的探測大小,指定探測數(shù)據(jù)包的大小吓妆,以確定流信息(單位:字節(jié))
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", 2048);
// 需要準(zhǔn)備好后自動播放
// 1.播放器準(zhǔn)備好后立即播放 0.播放器準(zhǔn)備好后不會自動開始播放赊时,需要手動啟動
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 1);
// 啟用或禁用硬件解碼
// 1.啟用硬件解碼;0.使用軟件解碼
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
// 關(guān)閉播放器緩沖耿战,減少延遲
// 0.禁用數(shù)據(jù)包緩沖蛋叼,可以降低播放延遲
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0);
// 設(shè)置重連次數(shù)
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "reconnect", 5);
// 設(shè)置緩存最長時間
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", 3000);
// 設(shè)置緩存檢測間隔配置
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "cache_check_period", 0);
// 設(shè)置緩存刪除間隔配置
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "cache_delete_period", 10000);
// 設(shè)置是否開啟環(huán)路過濾
// 0.開啟焊傅,畫面質(zhì)量高剂陡,解碼開銷大
// 48.關(guān)閉狈涮,畫面質(zhì)量差點,解碼開銷小
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
4.2 編譯參數(shù)
#! /usr/bin/env bash
#--------------------
# Standard options:
export COMMON_FF_CFG_FLAGS=
# Licensing options:
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-gpl"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-nonfree"
# Configuration options:
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-runtime-cpudetect"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-gray"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-swscale-alpha"
# Program options:
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-programs"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffmpeg"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffplay"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffprobe"
# Documentation options:
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-doc"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-htmlpages"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-manpages"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-podpages"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-txtpages"
# Component options:
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avdevice"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avcodec"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avformat"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avutil"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swresample"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swscale"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-postproc"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avfilter"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avresample"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-network"
# Hardware accelerators:
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-d3d11va"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dxva2"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vaapi"
#export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vda"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vdpau"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-videotoolbox"
# Individual component options:
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-encoders"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-encoder=png"
# ./configure --list-decoders
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-decoders"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=aac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=aac_latm"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=flv"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h264"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mp3*"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp6f"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=flac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=hevc"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp8"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp9"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h263"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h263i"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h263p"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mpeg4"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mjpeg"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=ijk*"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-hwaccels"
# ./configure --list-muxers
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-muxers"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-muxer=mp4"
# ./configure --list-demuxers
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-demuxers"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=aac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=concat"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=data"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=flv"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=hls"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=live_flv"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mov"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mp3"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegps"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegts"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegvideo"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=flac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=hevc"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=webm_dash_manifest"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpeg4"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=sdp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mjpeg"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=avi"
# ./configure --list-parsers
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-parsers"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=aac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=aac_latm"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=h264"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=flac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=hevc"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=mpeg4"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=mpeg4video"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=mpegvideo"
# ./configure --list-bsf
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-bsfs"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=chomp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=dca_core"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=dump_extradata"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=hevc_mp4toannexb"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=imx_dump_header"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mjpeg2jpeg"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mjpega_dump_header"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mov2textsub"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mp3_header_decompress"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mpeg4_unpack_bframes"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=noise"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=remove_extradata"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=text2movsub"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=vp9_superframe"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=eac3_core"
# ./configure --list-protocols
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocols"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=async"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=bluray"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=concat"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=crypto"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=ffrtmpcrypt"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=ffrtmphttp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=gopher"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=icecast"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=librtmp*"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=libssh"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=md5"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmsh"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmst"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtmp*"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmpt"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=sctp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=srtp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=subfile"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=unix"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-devices"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-filters"
# External library support:
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-iconv"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-audiotoolbox"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-videotoolbox"
# Developer options (useful when working on FFmpeg itself):
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-linux-perf"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bzlib"
5.寫在最后
GitHub傳送門:https://github.com/alidili/ijkplayer
到這里鸭栖,IjkPlayer源碼的RTMP追幀優(yōu)化就完成了歌馍,有問題可以給我留言評論,謝謝晕鹊。