Skip to content

Commit

Permalink
Kill the 1e8 times tries, refine PlayThread's logic
Browse files Browse the repository at this point in the history
The "PlayThread's logic" are the functions `audio_decode_frame()` and `packet_queue_get()`.

1. `audio_clock` will store the position in millisecond and `qint64` type.
2. the 1e8 times attempts is NOT ok.
3. `packet_queue_get()` should return `-1` if something goes wrong.
  • Loading branch information
pzhlkj6612 committed Jan 11, 2020
1 parent dd15503 commit 0175326
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 60 deletions.
84 changes: 29 additions & 55 deletions Entities/MusicPlayer/musicPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
ret = 1;
break;
} else if (!block) {
ret = 0;
ret = -1;
break;
} else
{
Expand Down Expand Up @@ -142,87 +142,58 @@ void destroy_queue_context(PacketQueue* q)

int PlayThread::audio_decode_frame(mediaState* MS, uint8_t* audio_buf)
{
static AVFrame *pframe=NULL; //一帧
static SwrContext*pSwr_ctx=NULL; //转换
AVFrame *pframe=NULL; //一帧
SwrContext*pSwr_ctx=NULL; //转换
AVPacket packet; //

int decodeLen=0;
int got_frame = 0;
int audio_pkt_size=0;
uint8_t* audio_pkt_data=NULL;

if(pframe)
av_frame_free(&pframe);
pframe=av_frame_alloc();
int returns = -1; //除非音频解码成功返回音频数据,否则返回 -1

while (true)
{
if (packet_queue_get(&MS->audioq, &packet, 0) < 0)
{
return -1;
break;
}
audio_pkt_data =packet.data;
audio_pkt_size = packet.size;

if (packet.pts != AV_NOPTS_VALUE)
if (packet.pts == AV_NOPTS_VALUE)
{
break;
}

//方式一:
//packet->pts 时间基于 AVStream->time_base units
//外部时间基于 1/AV_TIME_BASE 即 1微秒
//使用 av_rescale_q 转换得到 微秒时间
AVRational aVRational = { 1, AV_TIME_BASE };
int64_t res = av_rescale_q(packet.pts, pFormatCtx->streams[audioStream]->time_base, aVRational);


static int64_t lastRes = 0; //用于记录最后一次的时间
static int64_t tryTimes = 0;

if (lastRes != res) //与上次时间不同时,发送位置改变信号
{
MS->audio_clock = res * 1.0 / 1000;
lastRes = res;
tryTimes = 0;
}
else
{
tryTimes++;
//wanted_spec.callback = fillAudio 会在PacketQueue 队列中认为寻找数据,认为1亿次获取如果没有结果则意味着音乐结束
if (tryTimes >= 100000000LL)
{
qDebug() << "no data in list for 1e8 times access";
AGStatus = AGS_FINISH;
}
}
//外部时间基于 1/1000 即 1毫秒
//使用 av_rescale_q 转换得到 毫秒时间
AVRational aVRational = { 1, 1000 };
qint64 res = av_rescale_q(packet.pts, pFormatCtx->streams[audioStream]->time_base, aVRational);
MS->audio_clock = res;

//方式二:
//MS->audio_clock = (double)av_q2d(MS->aStream->time_base) * (double)packet.pts;
//MS->audio_clock *= 1000;

// AGStatus 由 AGS_SEEK 到 AGS_PLAYING 后, MS->audio_clock 才是拿到 seek 后的时间。
// 当然,通常在进入这个判断分支前 AGStatus 已是 AGS_PLAYING ,但仍有极少对立情况出现(出现频率为 2/193)。
// if(logAudio && getAGStatus() != AGS_SEEK)
if(logAudio)
{
logAudio = false;
qDebug() << "to " <<MS->audio_clock ;
}
}

while (audio_pkt_size > 0)
if (packet.size > 0)
{
decodeLen = avcodec_decode_audio4(MS->acct, pframe, &got_frame, &packet);
pframe=av_frame_alloc();
int got_frame;
int decodeLen = avcodec_decode_audio4(MS->acct, pframe, &got_frame, &packet);
if (decodeLen < 0) // 出错,跳过
break;

audio_pkt_data += decodeLen;
audio_pkt_size -= decodeLen;

if (pframe->channels > 0 && pframe->channel_layout == 0)
pframe->channel_layout = av_get_default_channel_layout(pframe->channels);
else if (pframe->channels == 0 && pframe->channel_layout > 0)
pframe->channels = av_get_channel_layout_nb_channels(pframe->channel_layout);


if (pSwr_ctx)
swr_free(&pSwr_ctx);
pSwr_ctx = swr_alloc_set_opts(nullptr, MS->wanted_frame->channel_layout,
(AVSampleFormat)MS->wanted_frame->format,
MS->wanted_frame->sample_rate,
Expand All @@ -237,11 +208,14 @@ int PlayThread::audio_decode_frame(mediaState* MS, uint8_t* audio_buf)
if (len2 < 0)
break;

av_free_packet(&packet);
return MS->wanted_frame->channels * len2 * av_get_bytes_per_sample((AVSampleFormat)MS->wanted_frame->format);
returns = MS->wanted_frame->channels * len2 * av_get_bytes_per_sample((AVSampleFormat)MS->wanted_frame->format);
}
break;
}
return -1;
swr_free(&pSwr_ctx);
av_frame_free(&pframe);
av_packet_unref(&packet);
return returns;
}


Expand Down Expand Up @@ -309,9 +283,9 @@ int PlayThread::getMsDuration() //获得毫秒为度量的总长度
}


int PlayThread::getCurrentTime()
qint64 PlayThread::getCurrentTime()
{
return static_cast<int>(m_MS.audio_clock);
return m_MS.audio_clock;
}

bool PlayThread::getIsDeviceInit()
Expand Down Expand Up @@ -965,7 +939,7 @@ quint64 MusicPlayer::duration()
}

//获得当总位置(单位 毫秒)
quint64 MusicPlayer::position()
qint64 MusicPlayer::position()
{
return m_position;
}
Expand Down
10 changes: 5 additions & 5 deletions Entities/MusicPlayer/musicPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ typedef struct{
AVStream *vStream;
PacketQueue audioq; //音频队列

double audio_clock; //储存毫秒时间
qint64 audio_clock; //储存毫秒时间
uint8_t volume;

PlayThread* playThread;
Expand Down Expand Up @@ -127,7 +127,7 @@ class PlayThread: public QThread
void setVolume(int value);

int getMsDuration();//获得毫秒为度量的总长度
int getCurrentTime(); //获得当前毫秒时间
qint64 getCurrentTime(); //获得当前毫秒时间

bool getIsDeviceInit();//实现互斥访问 isDeviceInit 的接口

Expand Down Expand Up @@ -257,7 +257,7 @@ class MusicPlayer :public QObject
void audioPause(); //暂停
void audioFinish(bool isEndByForce ); //播放完毕
void durationChanged(qint64); //总长发生改变(单位 毫秒)
void positionChanged(int); //位置发生改变(单位 毫秒)
void positionChanged(qint64); //位置发生改变(单位 毫秒)
void volumeChanged(int); //音量大小发生改变,范围 0-128
void errorOccur(int errorCode, QString msg); //发生错误

Expand Down Expand Up @@ -290,7 +290,7 @@ public slots:
void setVolume(int volume); //音量大小范围 0-128
int getVolume();
quint64 duration(); //获得当总时长(单位 毫秒)
quint64 position(); //获得当总位置(单位 毫秒)
qint64 position(); //获得当总位置(单位 毫秒)

void setNotifyInterval(int msec); //设置通知间隔(歌曲位置进度)
Status state();
Expand All @@ -310,7 +310,7 @@ private slots:

private:
QString musicPath;
quint64 m_position; //当前时间(单位 毫秒)
qint64 m_position; //当前时间(单位 毫秒)

int m_volume;

Expand Down

0 comments on commit 0175326

Please sign in to comment.