因?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
- 先在構(gòu)造函數(shù)中初始化mutex和cond恕刘,然后在析構(gòu)函數(shù)中回收;
- 完成入隊(duì)出隊(duì)操作抒倚,在這個(gè)過(guò)程中創(chuàng)建一個(gè)全局變量的類JfPlayStatus褐着,控制是否退出
- 在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分支