轉載註明出處:http://www.cnblogs.com/renhui/p/6510872.htmlhtml
以前使用IjkPlayer作播放器的使用的時候,在作倍速播放的時候,發現播放的聲音音調明顯變高了。問題的詳情參見#2930、#2785等。android
在解決問題以前首先對倍速的代碼作一次追蹤git
a. Android應用中Java層面調用的代碼:github
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); }
b.找到C庫裏面對應的方法:_setPropertyFloat (ijkplayer_jni.c)api
static void ijkMediaPlayer_setPropertyFloat(JNIEnv *env, jobject thiz, jint id, jfloat value) { IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: setPropertyFloat: null mp", LABEL_RETURN); ijkmp_set_property_float(mp, id, value); LABEL_RETURN: ijkmp_dec_ref_p(&mp); return; }
c.找到C庫中的對應的方法:ijkmp_set_property_float(ijkplayer.c)tcp
void ijkmp_set_property_float(IjkMediaPlayer *mp, int id, float value) { assert(mp); pthread_mutex_lock(&mp->mutex); ffp_set_property_float(mp->ffplayer, id, value); pthread_mutex_unlock(&mp->mutex); }
d.找到C庫中對應的方法:ffp_set_property_float(ff_ffplay.c)ide
void ffp_set_property_float(FFPlayer *ffp, int id, float value) { switch (id) { case FFP_PROP_FLOAT_PLAYBACK_RATE: ffp_set_playback_rate(ffp, value); break; case FFP_PROP_FLOAT_PLAYBACK_VOLUME: ffp_set_playback_volume(ffp, value); break; default: return; } }
e.找到C庫中對應的方法ffp_set_playback_rate:(ff_ffplay.c)學習
void ffp_set_playback_rate(FFPlayer *ffp, float rate) { if (!ffp) return; ffp->pf_playback_rate = rate; ffp->pf_playback_rate_changed = 1; }
追蹤完畢,咱們發現,基本上在Java層設置的倍速代碼,會被一層一層的傳遞到FFPlayer上面去。在IjkPlayer 0.7.9版本以前,能夠說,咱們對變調的問題,沒有頭緒,由於IjkPlayer將音頻的處理模塊直接調用系統的音頻處理模塊進行輸出,這樣的話,咱們就能夠看到在Android 6.0如下的手機在用IjkPlayer跑倍速的時候,出現音調變高的狀況。ui
近期,IjkPlayer的github上面發佈了最新版本0.7.9版本。url
下面引用一下IjkPlayer近幾個版本的changelog(Android相關的):
tag k0.7.9
ffmpeg: add tcp timeout control // 增長TCP超時控制邏輯
android: support soundtouch // Android端 支持soundtouch機制
tag k0.7.8
ffplay: support accurate seek // ffplay 支持更加精確的seek
ijkio: fix some issue // 修復一些問題
發現,0.7.9版本支持了soundtouch機制了。並且給出了開啓soundtouch機制的方式。
{ "soundtouch", "SoundTouch: enable", OPTION_OFFSET(soundtouch_enable), OPTION_INT(0, 0, 1) }
若是不開啓,在音頻播放的時候,仍是使用系統提供的api作播放處理(那麼聲調問題仍是存在)。開啓後,若是不對IjkPlayer C層面的邏輯作更改,也會有聲調的問題(由於B站對倍速的要求就是變調)。
那麼後續的工做就是先了解soundtouch而後對IjkPlayer的代碼作相關的調整。
瞭解和學習souchtouch:在 http://www.surina.net/soundtouch/index.html (官網) 裏面瞭解和學習。輔助學習的博客:http://www.cnblogs.com/wangguchangqing/p/6003087.html。
同步下來0.7.9版本的代碼後,能夠看到,在extra目錄下增長了soundtouch目錄,這個目錄下面就是soundtouch相關的邏輯。通過瀏覽代碼發現只須要去調整soundtouch/source/SoundStretch/main.cpp裏面的代碼:
pSoundTouch->setSampleRate(sampleRate); pSoundTouch->setChannels(channels); pSoundTouch->setTempoChange(params->tempoDelta); pSoundTouch->setPitchSemiTones(0); // 更改這裏,其餘不變 pSoundTouch->setRateChange(params->rateDelta);
調用從新打so,引入,Java層開啓soundtouch
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", 1);
使用倍速,此時變調的問題,應該解決了。
~~~~~~~~~~~~~~~~~~~~分割線~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
目前Ijk版本爲0.8.1版本,這個版本下,不去作上面的那些事情,只須要設置1,就爲變速變調的狀態。
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", 1);
設置0,就是變速不變調的狀態,
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", 1);
固然,若是按照上面的更改修改了C代碼了,也能夠,只不過,無論設置多少,都爲變速不變調的狀態了。