美文网首页
Android万能音频播放器02--队列缓存AVPacket

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

作者: 张俊峰0613 | 来源:发表于2019-01-04 16:56 被阅读0次

    因为解码获取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分支

    相关文章

      网友评论

          本文标题:Android万能音频播放器02--队列缓存AVPacket

          本文链接:https://www.haomeiwen.com/subject/hptkrqtx.html