開源播放器 ijkplayer (二) :ijkplayer倍速變調問題解決方案


轉載注明出處:http://www.cnblogs.com/renhui/p/6510872.html

之前使用IjkPlayer做播放器的使用的時候,在做倍速播放的時候,發現播放的聲音音調明顯變高了。問題的詳情參見Bilibili/ijkplayer#2930#2785等。

在解決問題之前首先對倍速的代碼做一次追蹤

a. Android應用中Java層面調用的代碼:

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)

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)

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

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跑倍速的時候,出現音調變高的情況。

近期,IjkPlayer的github上面發布了最新版本0.7.9版本。

下面引用一下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代碼了,也可以,只不過,不管設置多少,都為變速不變調的狀態了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM