在做音頻播放的時(shí)候,很多公司使用的是開源的ijkplayer播放器,ijkplayer底層是基于ffmpeg,在某機(jī)型上面可能常常遇到各種問題。今天整理了大家在使用ijkplayer中遇到的問題,以及根據(jù)ijkplayer社區(qū)issue和solution方案。如下:
1、直播技術(shù)總結(jié)(三)ijkplayer的一些問題優(yōu)化記錄
https://blog.csdn.net/hejjunlin/article/details/57075026
2、視頻直播技術(shù)(四):使用Ijkplayer播放直播視頻
https://www.cnblogs.com/renhui/p/6420140.html
3、IJKPlayer問題集錦之不定時(shí)更新- http://www.lxweimin.com/p/220b00d00deb
4、直播技術(shù)總結(jié)(三)ijkplayer的一些問題優(yōu)化記錄- http://blog.csdn.net/hejjunlin/article/details/57075026
5、ijkplayer rtmp秒開
ijkplayer設(shè)置rtmp秒開,可以讓rtmp加載時(shí)間從5~10秒縮短到1s以內(nèi),以達(dá)到秒開且低延遲的目的:
IjkMediaPlayer ijkMediaPlayer = null;
ijkMediaPlayer = new IjkMediaPlayer();
ijkMediaPlayer.setOption(1, "analyzemaxduration", 100L);
ijkMediaPlayer.setOption(1, "probesize", 10240L);
ijkMediaPlayer.setOption(1, "flush_packets", 1L);
ijkMediaPlayer.setOption(4, "packet-buffering", 0L);
ijkMediaPlayer.setOption(4, "framedrop", 1L);
6、ijkplayer實(shí)時(shí)
播放rtmp等實(shí)時(shí)性要求很高的流媒體時(shí)候,會(huì)出現(xiàn)10S左右的延遲,原因是因?yàn)榧恿司彌_區(qū)處理,可以把其緩存設(shè)置變小,達(dá)到實(shí)時(shí)的效果:
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 8);
ijkMediaPlayer.setOption(1, "analyzemaxduration", 100L);
ijkMediaPlayer.setOption(1, "probesize", 10240L);
ijkMediaPlayer.setOption(1, "flush_packets", 1L);
ijkMediaPlayer.setOption(4, "packet-buffering", 0L);
ijkMediaPlayer.setOption(4, "framedrop", 1L);
7、快速起直播流:
直播技術(shù)總結(jié)(五)如何快速起播直播流- http://blog.csdn.net/hejjunlin/article/details/72860470
這里優(yōu)化后者,主要修改兩個(gè)參數(shù),一個(gè)是probesize
,一個(gè)是analyzeduration
,分別用來(lái)控制其讀取的數(shù)據(jù)量大小和時(shí)長(zhǎng)。減少 probesize 和 analyzeduration
可以降低avformat_find_stream_info
的函數(shù)耗時(shí),達(dá)到起播快
ijkMediaPlayer.setOption(1,"analyzemaxduration",xxx);
ijkMediaPlayer.setOption(1,"probesize",xxx);
8、卡頓優(yōu)化和秒開,弱網(wǎng)優(yōu)化
- ijkplayer 解決rtmp 延遲長(zhǎng)的問題,達(dá)到秒開的結(jié)果- https://blog.csdn.net/yyhjifeng/article/details/71191950
- ijkplayer直播播放器使用經(jīng)驗(yàn)之談-卡頓優(yōu)化和秒開實(shí)現(xiàn)- https://blog.csdn.net/cmshao/article/details/80149176
9、ijkplayer丟幀的處理方案http://www.lxweimin.com/p/ecf51ee32589
直播的延遲,如果延遲過大,可以采取兩種策略,一種是丟幀,一種是追幀。我們可以考慮丟音頻包來(lái)實(shí)現(xiàn),音頻包不不在關(guān)鍵幀的問題,丟起來(lái)比較好操作,然后因?yàn)橐曨l同步到音頻,所以視頻會(huì)追幀,也會(huì)跟上來(lái)。
10、使用Ijkplayer倍速變調(diào)問題解決方案- https://www.cnblogs.com/renhui/p/6510872.html
public void setSpeed(float speed) {
_setPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, speed);
}
public float getSpeed(float speed) {
return _getPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, .0f);
}
11、ijkPlayer中的錯(cuò)誤碼:
IJKMEDIA: SDL_JNI_DetachThreadEnv
ijkplayer如何斷掉握手 Android ? ijkplayer如何釋放連接 Android ?
/*
* Do not change these values without updating their counterparts in native
*/
int MEDIA_INFO_UNKNOWN = 1;//未知信息
int MEDIA_INFO_STARTED_AS_NEXT = 2;//播放下一條
int MEDIA_INFO_VIDEO_RENDERING_START = 3;//視頻開始整備中,準(zhǔn)備渲染
int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;//視頻日志跟蹤
int MEDIA_INFO_BUFFERING_START = 701;//開始緩沖中 開始緩沖
int MEDIA_INFO_BUFFERING_END = 702;//緩沖結(jié)束
int MEDIA_INFO_NETWORK_BANDWIDTH = 703;//網(wǎng)絡(luò)帶寬,網(wǎng)速方面
int MEDIA_INFO_BAD_INTERLEAVING = 800;//
int MEDIA_INFO_NOT_SEEKABLE = 801;//不可設(shè)置播放位置,直播方面
int MEDIA_INFO_METADATA_UPDATE = 802;//
int MEDIA_INFO_TIMED_TEXT_ERROR = 900;
int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901;//不支持字幕
int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;//字幕超時(shí)
int MEDIA_INFO_VIDEO_INTERRUPT= -10000;//數(shù)據(jù)連接中斷,一般是視頻源有問題或者數(shù)據(jù)格式不支持,比如音頻不是AAC之類的
int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;//視頻方向改變,視頻選擇信息
int MEDIA_INFO_AUDIO_RENDERING_START = 10002;//音頻開始整備中
int MEDIA_ERROR_SERVER_DIED = 100;//服務(wù)掛掉,視頻中斷,一般是視頻源異常或者不支持的視頻類型。
int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;//數(shù)據(jù)錯(cuò)誤沒有有效的回收
int MEDIA_ERROR_IO = -1004;//IO 錯(cuò)誤
int MEDIA_ERROR_MALFORMED = -1007;
int MEDIA_ERROR_UNSUPPORTED = -1010;//數(shù)據(jù)不支持
int MEDIA_ERROR_TIMED_OUT = -110;//數(shù)據(jù)超時(shí)
Error (-10000,0)
12、ijkplayer 使用經(jīng)驗(yàn):
a、IJKPlayer 不像系統(tǒng)播放器會(huì)給你旋轉(zhuǎn)視頻角度,所以你需要通過onInfo的what == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED去獲取角度,自己旋轉(zhuǎn)畫面;或者開啟硬解硬解碼,不過硬解碼容易造成黑屏無(wú)聲,諸位慎重啊O__O "…。
mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
mediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
b、IJKPlayer 出現(xiàn)黑色有聲音沒圖像,看看你的視頻編碼是不是H264,pixel format是否存在,音頻編碼是不是AAC?默認(rèn)IJKPlayer是不支持3pg(支持它干啥(?-?*)?),不支持mepg(比如這個(gè)庫(kù)RecordVideoDemo ),不支持AMR。所以如果你真的想要支持,那么參考這個(gè)#1961,打開mpeg支持,重新編ffmpeg,然后通過硬解碼播放mpeg;或者通過系統(tǒng)的錄制VideoRecord;或者選另外的JAVACV錄制封裝FFmpegRecorder。
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec_mpeg4", 1);
c、快進(jìn)和慢放接口,只支持API23以上,23以下的支持,是需要自己配置ffmpeg支持avfilter,不過可能會(huì)出現(xiàn)聲音顫抖等問題,官方說(shuō)不穩(wěn)定,參考#1690。
Tryavfilter but the audio sounds shaking = = For avfilter, only support software decoder.
d、暫停的時(shí)候,退到后臺(tái)再回到前臺(tái),畫面黑了?這時(shí)候個(gè)人處理方式是,可以在暫停的時(shí)候,通過TextureView.getBitmap(point.x, point.y);獲取到暫停的畫面,用ImageView顯示它,在onSurfaceTextureUpdated的時(shí)候隱藏ImageView,來(lái)實(shí)現(xiàn)畫面的銜接。
e、一些視頻返回碼
int MEDIA_INFO_VIDEO_RENDERING_START = 3;//視頻準(zhǔn)備渲染
int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;//數(shù)據(jù)錯(cuò)誤沒有有效的回收
int MEDIA_INFO_BUFFERING_START = 701;//開始緩沖
int MEDIA_INFO_BUFFERING_END = 702;//緩沖結(jié)束
int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;//視頻選擇信息
int MEDIA_ERROR_SERVER_DIED = 100;//視頻中斷,一般是視頻源異常或者不支持的視頻類型。
int MEDIA_ERROR_IJK_PLAYER = -10000,//一般是視頻源有問題或者數(shù)據(jù)格式不支持,比如音頻不是AAC之類的
MediaPlayer Error (-10000,0), 視頻播放過程中出錯(cuò)了,可能是視頻的原因,播放器內(nèi)部錯(cuò)誤
f、某些視頻在SeekTo的時(shí)候,會(huì)跳回到拖動(dòng)前的位置,這是因?yàn)橐曨l的關(guān)鍵幀的問題,通俗一點(diǎn)就是FFMPEG不兼容,視頻壓縮過于厲害,seek只支持關(guān)鍵幀,出現(xiàn)這個(gè)情況就是原始的視頻文件中i 幀比較少,播放器會(huì)在拖動(dòng)的位置找最近的關(guān)鍵幀,目前么,IJKPlayer無(wú)解。
g、下載速度可以通過IjkMediaPlayer的getTcpSpeed獲取。
h、高分辨率開啟硬解碼,不支持的話會(huì)自動(dòng)切換到軟解,就算開啟mediacodec,如果設(shè)備不支持,顯示的解碼器也是avcodec軟解。
i、ijkMediaPlayer.setOption可配置的對(duì)應(yīng)頭文件參考:ff_ffplay_options。
j、緩沖進(jìn)度條不到100,官方表示我就不保證都100,所以一般我都是:
//95這個(gè)數(shù)值可能不準(zhǔn)確,有些時(shí)候可能還需要低一些
if (secProgress > 95) secProgress = 100;
k、上面a、b、f的問題,在IJK封裝的EXOPlayer和MediaPlayer都不會(huì)有問題,兼容上確實(shí)強(qiáng)過IJKPlayer,但是它們?cè)诩?xì)節(jié)上,卻沒有IJK處理的好,如EXOPlayer:退到后再回到前臺(tái)、切換渲染控件的黑屏一段時(shí)間問題,除了用seekto之外目前沒發(fā)現(xiàn)其他辦法,這樣的體驗(yàn)讓我最后還是選擇IJKPlayer。
l、設(shè)置cookie 可以通過ijkPlayer的public void setDataSource(String path, Map<String, String> headers) 的header實(shí)現(xiàn)設(shè)置,參考ijkPlayer的issues-1150,headers也是在內(nèi)部被轉(zhuǎn)化為何issuses一樣的setOption方法。
13、ijkplayer常見問題以及解決方案
a、ijkplayer播放rtmp直播流,延遲明顯- https://github.com/Bilibili/ijkplayer/issues/210
b、全屏播放
c、有時(shí)候會(huì)開始直播時(shí)出現(xiàn)黑屏
d、有時(shí)候會(huì)出現(xiàn)花屏
e、解碼方式設(shè)置
f、如何區(qū)分點(diǎn)播直播
g、是否需要開啟硬件加速
h、How to set up only listen to the sound does not show video?- https://github.com/Bilibili/ijkplayer/issues/1074
i、如何設(shè)置后臺(tái)播放
j、視頻加載速度慢
The traffic speed is mostly depending on the quality of video CDN, not player itself.
k、怎么靜音 和非靜音
mute/unmute system volume.There is no mute/unmute API in ijkplayer.
l、視頻黑屏,但是有聲音
確定下視頻源的編碼方式,ijk默認(rèn)只帶了h264解碼code
m、適配問題,對(duì)于不同的cpu架構(gòu),需要編譯不同的so庫(kù)
n、播放視頻有的設(shè)備聲畫不同步
o、如何查看m3u8時(shí)長(zhǎng)
cat game05.m3u8 | grep EXTINF | wc -l 32
p、how to change the video quality?
Video quality is determined when being encoded.I don’t think it can be changed by player.
q、為什么往前拖動(dòng)進(jìn)度條后,還會(huì)往后退幾秒
seek只支持關(guān)鍵幀,出現(xiàn)這個(gè)情況就是原始的視頻文件中i 幀比較少,播放器會(huì)在拖動(dòng)的位置找最近的關(guān)鍵幀。
r、how to change URL when ijkplayer is playing RTMP video
Create new player.
s、怎樣添加字幕呢?
如果希望字幕時(shí)間精確,可以在native層做解析和時(shí)間同步,到了時(shí)間后回調(diào)給java層,一般字幕文件加載都是在java層做的,解析文件格式,然后按照時(shí)間區(qū)間來(lái)顯示。
t、如何設(shè)置硬解?
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, “mediacodec”, 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "analyzeduration", "2000000");
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "probsize", "4096");
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 0);
u、http重定向到rtmp/Https,ijkplayer無(wú)法播放視頻
ijkMediaPlayer.setOption( IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1);
v、android mediaPlayer error (-38,0) prepare()調(diào)用報(bào)錯(cuò)解決辦法:
出現(xiàn)這個(gè)錯(cuò)誤發(fā)現(xiàn)在mediaPlayer.reset()后調(diào)用了mediaPlayer.getDuration()在沒有給mediaPlayer對(duì)象設(shè)置數(shù)據(jù)源之前,是不能使用getDuration等這些方法的.需要檢查一下在設(shè)置MediaPlayer的數(shù)據(jù)源時(shí),使用的是那種方式:
- 1、在初始化MediaPlayer時(shí),通過create方法設(shè)置數(shù)據(jù)源。則不能寫MediaPlayer.prepare()方法,這時(shí),會(huì)報(bào)錯(cuò)。
- 2、如果是使用MediaPlayer構(gòu)造函數(shù)初始化MediaPlayer,然后通過setDataSource方法設(shè)置數(shù)據(jù)源時(shí),就需要在start()之前,使用MediaPlayer.prepare()方法,對(duì)數(shù)據(jù)源進(jìn)行一次編譯。能夠避免出現(xiàn)(-38,0)這種錯(cuò)誤。