Android萬(wàn)能音頻播放器02--隊(duì)列緩存AVPacket

因?yàn)榻獯a獲取AVPacket需要耗費(fèi)一定的時(shí)間搬素,為了達(dá)到更好地播放效果
(流暢度)绷耍,需要把解碼出來(lái)的AVPacket先緩存到隊(duì)列中祈匙,播放時(shí)直接
從隊(duì)里里面取忽刽。

1天揖、隊(duì)列

一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu)

1、頭文件
#include “queue”

2跪帝、創(chuàng)建隊(duì)列
std::queue<T> queue;

3今膊、入隊(duì)
queue.push(t);

4、出隊(duì)
T t = queue.front();//獲取隊(duì)頭
queue.pop();

1.1伞剑、AVPacket隊(duì)列封裝

1.1.1斑唬、入隊(duì):

putAvpacket(AVPacket *avPacket)
{
    //加鎖
    pthread_mutex_lock(&mutexPacket);
    //入隊(duì)
    queuePacket.push(avPacket);
    //發(fā)送消息給消費(fèi)者
    pthread_cond_signal(&condPacket);
    //解鎖
    pthread_mutex_unlock(&mutexPacket);
}

1.1.2、出隊(duì)

getAvpacket(AVPacket *avPacket) 
{
    pthread_mutex_lock(&mutexPacket);
    while(playStatus != NULL && !playStatus->exit)
    {
        if(queuePacket.size() > 0)
        {
            AVPacket *pkt = queuePacket.front();
            if(av_packet_ref(avPacket, pkt) == 0) //把pkt的內(nèi)存數(shù)據(jù)拷貝到avPacket內(nèi)存中
            {
                queuePacket.pop();
            }
            av_packet_free(&pkt);
            av_free(pkt);
            pkt = NULL;
            break;
        } else{
            pthread_cond_wait(&condPacket, &mutexPacket);
        }
    }
    pthread_mutex_unlock(&mutexPacket);
}

2黎泣、

創(chuàng)建隊(duì)列的C++類-JfQueue
JfQueue.h

class JfQueue {

public:
    std::queue<AVPacket *> queuePacket;//存儲(chǔ)AVPacket的隊(duì)列
    pthread_mutex_t mutexPacket;//線程鎖
    pthread_cond_t condPacket;//消息
    JfPlayStatus *jfPlayStatus = NULL; //播放狀態(tài)

public:
    JfQueue(JfPlayStatus *jfPlayStatus);
    ~JfQueue();

    int putAVPacket(AVPacket *avPacket);//將AVPacket放進(jìn)隊(duì)列中
    int getAVPacket(AVPacket *avPacket);//從隊(duì)列中取出AVPacket
    int getQueueSize();
};

JfPlayStatus 是一個(gè)判斷是否退出的全局都要用到的類
JfPlayStatus.h

class JfPlayStatus {

public:
    bool exit;

public:
    JfPlayStatus();
};

JfPlayStatus.cpp

JfPlayStatus::JfPlayStatus() {
    exit = false;
}

主要實(shí)現(xiàn):JfQueue.cpp

  1. 先在構(gòu)造函數(shù)中初始化mutex和cond恕刘,然后在析構(gòu)函數(shù)中回收;
  2. 完成入隊(duì)出隊(duì)操作抒倚,在這個(gè)過(guò)程中創(chuàng)建一個(gè)全局變量的類JfPlayStatus褐着,控制是否退出
  3. 在JfAudio中創(chuàng)建一個(gè)JfQueue指針;
JfQueue::JfQueue(JfPlayStatus *jfPlayStatus) {

    this->jfPlayStatus = jfPlayStatus;
    pthread_mutex_init(&mutexPacket,NULL);
    pthread_cond_init(&condPacket,NULL);
}

JfQueue::~JfQueue() {
    pthread_mutex_destroy(&mutexPacket);
    pthread_cond_destroy(&condPacket);
}

int JfQueue::putAVPacket(AVPacket *avPacket) {
    pthread_mutex_lock(&mutexPacket);

    queuePacket.push(avPacket);
    if (LOG_DEBUG){
        LOGD("放入一個(gè)AVPacket到隊(duì)列中托呕,個(gè)數(shù)為 == %d",queuePacket.size());
    }

    pthread_cond_signal(&condPacket);//入隊(duì)完之后發(fā)一個(gè)信號(hào)

    pthread_mutex_unlock(&mutexPacket);
    return 0;
}

int JfQueue::getAVPacket(AVPacket *packet) {
    pthread_mutex_lock(&mutexPacket);

    while (jfPlayStatus != NULL && !jfPlayStatus->exit){
        if (queuePacket.size() > 0){
            AVPacket *avPacket = queuePacket.front();//取出來(lái)
            if (av_packet_ref(packet,avPacket) == 0){//把pkt的內(nèi)存數(shù)據(jù)拷貝到avPacket內(nèi)存中含蓉,只是拷貝了引用
                queuePacket.pop();
            }
            av_packet_free(&avPacket);//AVPacket中的第一個(gè)參數(shù),就是引用项郊,減到0才真正釋放
            av_free(avPacket);
            avPacket = NULL;

            if (LOG_DEBUG){
                LOGD("從隊(duì)列中取出一個(gè)AVPacket馅扣,還剩下%d個(gè)",queuePacket.size());
            }

            break;
        } else {
            pthread_cond_wait(&condPacket,&mutexPacket);
        }
    }

    pthread_mutex_unlock(&mutexPacket);
    return 0;
}

int JfQueue::getQueueSize() {
    int size = 0;
    pthread_mutex_lock(&mutexPacket);
    size = queuePacket.size();
    pthread_mutex_unlock(&mutexPacket);
    return size;
}

改JfFFmpeg.cpp

void JfFFmpeg::start() {
    if (audio == NULL) {
        if (LOG_DEBUG){
            LOGE("AUDIO == NULL");
        }
    }

    int count;
    while (1) {
        AVPacket *avPacket = av_packet_alloc();
        if (av_read_frame(pAFmtCtx,avPacket) == 0) {
            if (avPacket->stream_index == audio->streamIndex){
                count++;
                if (LOG_DEBUG) {
                    LOGD("解碼第%d幀",count);
                }
                audio->queue->putAVPacket(avPacket);
            } else {
                av_packet_free(&avPacket);
                av_free(avPacket);
                avPacket = NULL;
            }
        } else {
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = NULL;
            break;
        }
    }

    while (audio->queue->getQueueSize() > 0){
        AVPacket *avPacket = av_packet_alloc();
        audio->queue->getAVPacket(avPacket);
        av_packet_free(&avPacket);
        av_free(avPacket);
        avPacket = NULL;
    }

    if (LOG_DEBUG){
        LOGD("解碼完成");
    }
}

源碼地址:https://github.com/Xiaoben336/SuperAudioPlayer.git:pktQueue分支

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市着降,隨后出現(xiàn)的幾起案子差油,更是在濱河造成了極大的恐慌,老刑警劉巖鹊碍,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厌殉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡侈咕,警方通過(guò)查閱死者的電腦和手機(jī)公罕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)耀销,“玉大人楼眷,你說(shuō)我怎么就攤上這事⌒芪荆” “怎么了罐柳?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)狰住。 經(jīng)常有香客問(wèn)我张吉,道長(zhǎng),這世上最難降的妖魔是什么催植? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任肮蛹,我火速辦了婚禮勺择,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘伦忠。我一直安慰自己省核,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布昆码。 她就那樣靜靜地躺著气忠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赋咽。 梳的紋絲不亂的頭發(fā)上旧噪,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音冬耿,去河邊找鬼舌菜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛亦镶,可吹牛的內(nèi)容都是我干的日月。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼缤骨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼爱咬!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起绊起,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤精拟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后虱歪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜂绎,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年笋鄙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了师枣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡萧落,死狀恐怖践美,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情找岖,我是刑警寧澤陨倡,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站许布,受9級(jí)特大地震影響兴革,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜜唾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一杂曲、第九天 我趴在偏房一處隱蔽的房頂上張望箕昭。 院中可真熱鬧,春花似錦解阅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至朱转,卻和暖如春蟹地,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背藤为。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工怪与, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缅疟。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓分别,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親存淫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子耘斩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容