Android万能音频播放器02--队列缓存AVPacket

2019-01-04  本文已影响0人  张俊峰0613

因为解码获取AVPacket需要耗费一定的时间,为了达到更好地播放效果
(流畅度),需要把解码出来的AVPacket先缓存到队列中,播放时直接
从队里里面取。

1、队列

一种先进先出的数据结构

1、头文件
#include “queue”

2、创建队列
std::queue<T> queue;

3、入队
queue.push(t);

4、出队
T t = queue.front();//获取队头
queue.pop();

1.1、AVPacket队列封装

1.1.1、入队:

putAvpacket(AVPacket *avPacket)
{
    //加锁
    pthread_mutex_lock(&mutexPacket);
    //入队
    queuePacket.push(avPacket);
    //发送消息给消费者
    pthread_cond_signal(&condPacket);
    //解锁
    pthread_mutex_unlock(&mutexPacket);
}

1.1.2、出队

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的内存数据拷贝到avPacket内存中
            {
                queuePacket.pop();
            }
            av_packet_free(&pkt);
            av_free(pkt);
            pkt = NULL;
            break;
        } else{
            pthread_cond_wait(&condPacket, &mutexPacket);
        }
    }
    pthread_mutex_unlock(&mutexPacket);
}

2、

创建队列的C++类-JfQueue
JfQueue.h

class JfQueue {

public:
    std::queue<AVPacket *> queuePacket;//存储AVPacket的队列
    pthread_mutex_t mutexPacket;//线程锁
    pthread_cond_t condPacket;//消息
    JfPlayStatus *jfPlayStatus = NULL; //播放状态

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

    int putAVPacket(AVPacket *avPacket);//将AVPacket放进队列中
    int getAVPacket(AVPacket *avPacket);//从队列中取出AVPacket
    int getQueueSize();
};

JfPlayStatus 是一个判断是否退出的全局都要用到的类
JfPlayStatus.h

class JfPlayStatus {

public:
    bool exit;

public:
    JfPlayStatus();
};

JfPlayStatus.cpp

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

主要实现:JfQueue.cpp

  1. 先在构造函数中初始化mutex和cond,然后在析构函数中回收;
  2. 完成入队出队操作,在这个过程中创建一个全局变量的类JfPlayStatus,控制是否退出
  3. 在JfAudio中创建一个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("放入一个AVPacket到队列中,个数为 == %d",queuePacket.size());
    }

    pthread_cond_signal(&condPacket);//入队完之后发一个信号

    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();//取出来
            if (av_packet_ref(packet,avPacket) == 0){//把pkt的内存数据拷贝到avPacket内存中,只是拷贝了引用
                queuePacket.pop();
            }
            av_packet_free(&avPacket);//AVPacket中的第一个参数,就是引用,减到0才真正释放
            av_free(avPacket);
            avPacket = NULL;

            if (LOG_DEBUG){
                LOGD("从队列中取出一个AVPacket,还剩下%d个",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分支

上一篇下一篇

猜你喜欢

热点阅读